I’m developing a Go application that integrates with MongoDB to create, read, and delete images. I’ve set the connection pool to 4 for testing purposes, but I’ve noticed that the number of connections can go up to 10 even if I haven’t hit any endpoint related to MongoDB. If I don’t hit any endpoint, the number of connections stays between 2-3. There’s a connection leak in my code, and I’m having trouble figuring out how to release resources correctly to ensure that they are returned to the pool.

As the documentation says mongo-go driver is goroutine safe so I have a function that initialize mongo and set a global variable with the initialized mongo client

package persistence
import (
	"context"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"time"
var MongoClient *mongo.Client
func InitMongo(ctx context.Context, URI string) error {
	if MongoClient != nil {
		return nil
	serverAPI := options.ServerAPI(options.ServerAPIVersion1)
	opts := options.Client().ApplyURI(URI).SetServerAPIOptions(serverAPI)
	opts.SetMinPoolSize(10)
	opts.SetMaxPoolSize(100)
	opts.SetMaxConnIdleTime(2 * time.Second)
	// Create a new client and connect to the server
	client, err := mongo.Connect(ctx, opts)
	if err != nil {
		return err
	MongoClient = client
	// Send a ping to confirm a successful connection
	var result bson.M
	if err = client.Database("admin").RunCommand(context.TODO(), bson.D{{"ping", 1}}).Decode(&result); err != nil {
		return err
	return nil

and I use this function in the main to initialize it

func main() {
	configuration := config.NewEnvConfigs()
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	err = persistence.InitMongo(ctx, configuration.MongoDBURI)
	if err != nil {
		fmt.Println("Mongo not ready")
		panic(err)
	fmt.Println("mongo connected")
	defer func() {
		if err = persistence.MongoClient.Disconnect(context.TODO()); err != nil {
			panic(err)
	r := server.Routes()
	http.ListenAndServe("0.0.0.0:3333", r)

also the last piece of code that uses the mongo client is the handlers for images endpoints

package handlers
import (
	"context"
	"encoding/base64"
	"errors"
	"fmt"
	"github.com/bycultivaet/backend/internal/infrastructure/persistence"
	"github.com/go-chi/chi"
	"github.com/go-chi/render"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"io/ioutil"
	"mime/multipart"
	"net/http"
func GetImageByID() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		ctx, cancel := context.WithCancel(r.Context())
		defer cancel()
		Uuid := chi.URLParam(r, "uuid")
		_, err := uuid.Parse(Uuid)
		if err != nil {
			render.Status(r, 400)
			render.Respond(w, r, errors.New("invalid uuid").Error())
			return
		filter := bson.M{"uuid": Uuid}
		var result bson.M
		collection := persistence.MongoClient.Database("hassad-media").Collection("images")
		err = collection.FindOne(ctx, filter).Decode(&result)
		if err != nil {
			render.Status(r, 404)
			render.Respond(w, r, errors.New("image not found").Error())
			return
		imageData, ok := result["image"].(primitive.Binary)
		if !ok {
			render.Status(r, 500)
			render.Respond(w, r, errors.New("error parsing image").Error())
			return
		imageBase64 := base64.StdEncoding.EncodeToString(imageData.Data)
		render.Status(r, 200)
		render.JSON(w, r, map[string]string{"image": imageBase64})
func UploadImage() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		ctx, cancel := context.WithCancel(r.Context())
		defer cancel()
		cancelled := r.Context().Done()
		select {
		case <-cancelled:
			render.Status(r, 499)
			render.Respond(w, r, errors.New("request cancelled").Error())
			return
		default:
			err := r.ParseMultipartForm(10 << 20)
			if err != nil {
				render.Status(r, http.StatusBadRequest)
				render.Respond(w, r, err.Error())
				return
			file, _, err := r.FormFile("image")
			if err != nil {
				render.Status(r, http.StatusBadRequest)
				render.Respond(w, r, err.Error())
				return
			defer file.Close()
			Uuid, err := uuid.NewRandom()
			if err != nil {
				render.Status(r, http.StatusInternalServerError)
				render.Respond(w, r, errors.New("error generating uuid").Error())
				return
			// Pass the contents of the file to GetMongoDB
			_, err = UploadPhoto(file, Uuid.String(), ctx)
			if err != nil {
				render.Status(r, http.StatusInternalServerError)
				render.Respond(w, r, err.Error())
				return
			render.Status(r, http.StatusOK)
			render.JSON(w, r, map[string]string{"uuid": Uuid.String()})
func UploadPhoto(file multipart.File, uuid string, ctx context.Context) (interface{}, error) {
	imageBytes, err := ioutil.ReadAll(file)
	if err != nil {
		return nil, err
	imageDoc := bson.M{"image": imageBytes, "uuid": uuid}
	defer file.Close()
	collection := persistence.MongoClient.Database("hassad-media").Collection("images")
	data, err := collection.InsertOne(ctx, imageDoc)
	if err != nil {
		return 0, err
	fmt.Println("Inserted image into MongoDB!")
	fmt.Println(data.InsertedID)
	return data.InsertedID, nil
func DeleteImageByID() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		ctx, cancel := context.WithCancel(r.Context())
		defer cancel()
		uuid := chi.URLParam(r, "uuid")
		filter := bson.M{"uuid": uuid}
		collection := persistence.MongoClient.Database("hassad-media").Collection("images")
		res, err := collection.DeleteOne(ctx, filter)
		if err != nil {
			if res.DeletedCount == 0 {
				render.Status(r, 404)
				render.Respond(w, r, errors.New("image not found").Error())
				return
			render.Status(r, 500)
			render.Respond(w, r, err.Error())
			return
		render.JSON(w, r, map[string]string{"answer": "deleted"})

what I’m doing wrong closing the connections to be returned to the pool or any other configuration

I test my code by with python script that hits the endpoints excessively

Hey @Omar_Dawah, welcome and thanks for the question!

What you’re describing actually sounds like normal behavior. Additionally, the code you provided seems correct and shouldn’t cause a connection leak.

MongoDB drivers open a minimum of 2 monitoring connections to each node in a MongoDB database, plus at least 1 connection to each node for user operations. For example, if you’re connecting to a 3-node replica set, MongoDB drivers will open 6 total monitoring connections before you run any operations. Monitoring connections are used to track the state of the database to maximize availability during topology changes or unexpected disconnects.

Even though your description doesn’t sound like a connection leak, I have a few questions to help me understand your situation:

  • What version of the Go driver are you using?
  • What MongoDB topology are you connecting to? For example, is it a standalone node, a replica set, a sharded cluster, Atlas Serverless, or something else?
  • Are you connecting to a self-hosted or Atlas-hosted database?
  • Thanks!

    Thanks For Answering @Matt_Dale,
    1- go.mongodb.org/mongo-driver v1.12.0
    2- Mongo Cluster (The Free plan)
    3- Atlas-hosted database

    Another piece of information that may help you, is that on production I used to get connections up to 500 even if the max pool is 100 but after I have set opts.SetMaxConnIdleTime(2 * time.Second) it’s dropped to about 240-250 at the peak of using.
    also, I’m sure that there are no 240 hits to the Mongo endpoints

    Get started on your Generative AI adventure with Atlas Vector Search. Click here for more info.