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.