What's Actually Happening

MongoDB connection pool runs out of available connections, preventing new connections from being established. Applications fail with connection errors while the pool shows all connections are in use.

The Error You'll See

Connection pool exhausted:

```bash # Application error: MongoError: Connection pool for "mongodb://localhost:27017" exhausted

# MongoDB driver error: MongoTimeoutError: Connection pool exhausted, waiting for available connection timed out after 30000ms ```

Server logs:

```bash $ mongod --logpath /var/log/mongodb/mongod.log

[conn1234] connection refused because too many open connections: 819 ```

Connection statistics:

```javascript > db.serverStatus().connections

{ "current" : 1000, "available" : 0, "totalCreated" : 5000 } // available = 0 means pool exhausted ```

Why This Happens

  1. 1.Pool size too small - Not enough connections for workload
  2. 2.Connection leaks - Connections not returned to pool
  3. 3.Long-running queries - Connections held too long
  4. 4.Insufficient timeout - Connections not timing out
  5. 5.Max connections reached - Server limit hit
  6. 6.Connection storm - Sudden spike in concurrent requests

Step 1: Check Current Connection Status

```javascript // Check server connection stats db.serverStatus().connections

// Check connection pool stats (driver-specific) db.serverStatus().metrics.connection

// Count active connections by client db.currentOp({"active": true}).inprog.forEach(function(op) { print(op.client + " - " + op.active); })

// Check connection source db.currentOp().inprog.forEach(function(op) { if (op.client) print(op.client); })

// List all connections (admin) db.adminCommand({currentOp: 1, "$all": true})

// Check for idle connections db.currentOp({"active": false})

// Server status with connection details db.serverStatus({connections: 1, metrics: 1}) ```

Step 2: Check Pool Configuration

```javascript // Connection pool settings in driver:

// Node.js (mongodb driver): const client = new MongoClient(uri, { maxPoolSize: 100, // Maximum connections in pool minPoolSize: 10, // Minimum connections maintained maxIdleTimeMS: 60000, // Close idle connections after 60s waitQueueTimeoutMS: 30000, // Wait timeout for connection connectTimeoutMS: 30000, // Connection timeout socketTimeoutMS: 30000 // Socket timeout });

// Java driver: MongoClientSettings settings = MongoClientSettings.builder() .applyToConnectionPoolSettings(builder -> builder .maxSize(100) .minSize(10) .maxWaitTime(30, TimeUnit.SECONDS) .maxConnectionIdleTime(60, TimeUnit.SECONDS) .maxConnectionLifeTime(30, TimeUnit.MINUTES)) .build();

// Python (pymongo): client = MongoClient(uri, maxPoolSize=100, minPoolSize=10, maxIdleTimeMS=60000, waitQueueTimeoutMS=30000, connectTimeoutMS=30000, socketTimeoutMS=30000 ) ```

Step 3: Check Server Connection Limits

```bash # Check MongoDB max connections mongo --eval "db.serverStatus().connections"

# Check configured limit mongod --setParameter maxConns=1000

# Or in mongod.conf: net: maxIncomingConnections: 1000

# Check ulimit for MongoDB process cat /proc/$(pgrep mongod)/limits | grep "open files"

# Check system file descriptor limit ulimit -n

# Increase ulimit: # In /etc/security/limits.conf: mongodb soft nofile 65536 mongodb hard nofile 65536

# Or in mongod service file: [Service] LimitNOFILE=65536 ```

Step 4: Identify Connection Leaks

```javascript // Check for connections not being closed

// Common leak patterns:

// WRONG: Connection not closed async function query() { const client = new MongoClient(uri); await client.connect(); const result = await client.db().collection('users').find({}).toArray(); return result; // client.close() never called! }

// CORRECT: Always close connections async function query() { const client = new MongoClient(uri); try { await client.connect(); return await client.db().collection('users').find({}).toArray(); } finally { await client.close(); } }

// BETTER: Use connection pooling (singleton client) let cachedClient = null;

async function getClient() { if (!cachedClient) { cachedClient = new MongoClient(uri); await cachedClient.connect(); } return cachedClient; }

// Use withConnect wrapper const { withTransaction } = require('mongodb');

await withTransaction(client, async (session) => { // Transaction work }); ```

Step 5: Monitor Connection Pool

```javascript // Enable connection pool monitoring (Node.js driver) const client = new MongoClient(uri, { maxPoolSize: 100 });

// Monitor pool events client.on('connectionPoolCreated', (event) => { console.log('Pool created:', event); });

client.on('connectionCreated', (event) => { console.log('Connection created:', event.address); });

client.on('connectionReady', (event) => { console.log('Connection ready:', event.address); });

client.on('connectionClosed', (event) => { console.log('Connection closed:', event.address, event.reason); });

client.on('connectionCheckOutStarted', (event) => { console.log('Checking out connection'); });

client.on('connectionCheckOutFailed', (event) => { console.error('Checkout failed:', event.reason); });

client.on('connectionCheckedOut', (event) => { console.log('Connection checked out:', event.connectionId); });

client.on('connectionCheckedIn', (event) => { console.log('Connection checked in:', event.connectionId); });

// Get pool size metrics db.serverStatus().metrics.connection ```

Step 6: Fix Long-Running Queries

```javascript // Identify long-running operations db.currentOp({ "active": true, "secs_running": {"$gt": 30} })

// Kill long-running operations db.killOp(opId)

// Check slow queries db.system.profile.find({ millis: {$gt: 10000} }).sort({ts: -1}).limit(10)

// Enable profiling db.setProfilingLevel(1, { slowms: 1000 })

// Add query timeout db.collection.find({}).maxTimeMS(30000)

// Add index to improve query speed db.collection.createIndex({field: 1}) ```

Step 7: Configure Connection Timeouts

```javascript // Proper timeout configuration

const client = new MongoClient(uri, { // Connection timeouts connectTimeoutMS: 30000, // Time to establish connection socketTimeoutMS: 30000, // Time for socket operations

// Pool timeouts waitQueueTimeoutMS: 30000, // Time to wait for available connection maxIdleTimeMS: 60000, // Close idle connections after 60s maxConnectionLifeTimeMS: 1800000, // Close connections after 30 min

// Heartbeat heartbeatFrequencyMS: 10000, // Check connection health every 10s

// Pool sizing maxPoolSize: 100, minPoolSize: 10 });

// Server-side timeout configuration (mongod.conf): setParameter: cursorTimeoutMillis: 600000 maxTimeDefaultTimeLimit: 60000 ```

Step 8: Implement Connection Pooling Best Practices

```javascript // 1. Use a single MongoClient instance (connection pooling is per-client) // Global client instance let dbClient = null;

async function getDb() { if (!dbClient) { dbClient = new MongoClient(process.env.MONGODB_URI, { maxPoolSize: 50, minPoolSize: 10 }); await dbClient.connect(); } return dbClient.db(); }

// 2. Handle graceful shutdown process.on('SIGINT', async () => { if (dbClient) { await dbClient.close(); } process.exit(0); });

// 3. Use connection pooling for serverless // For AWS Lambda, use global client with lazy initialization let client = null;

exports.handler = async (event) => { if (!client) { client = new MongoClient(uri, { maxPoolSize: 10, minPoolSize: 0, maxIdleTimeMS: 60000 }); await client.connect(); } // Process event };

// 4. Monitor pool health setInterval(() => { const poolStats = client.db().admin().serverStatus().connections; console.log(Connections: ${poolStats.current}/${poolStats.current + poolStats.available}); }, 60000); ```

Step 9: Handle Connection Errors

```javascript // Robust connection handling with retry

async function connectWithRetry(uri, options = {}, maxRetries = 3) { let lastError;

for (let i = 0; i < maxRetries; i++) { try { const client = new MongoClient(uri, { ...options, serverSelectionTimeoutMS: 5000, connectTimeoutMS: 10000 }); await client.connect(); console.log('Connected to MongoDB'); return client; } catch (error) { lastError = error; console.error(Connection attempt ${i + 1} failed:, error.message); await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); } }

throw lastError; }

// Handle connection loss client.on('serverClosed', (event) => { console.log('Server closed, attempting reconnect'); });

// Use retryable reads/writes const client = new MongoClient(uri, { retryWrites: true, retryReads: true }); ```

Step 10: Monitor and Alert on Pool Exhaustion

```javascript // Create monitoring script const monitor = setInterval(async () => { try { const status = await db.admin().serverStatus(); const connections = status.connections;

const utilization = connections.current / (connections.current + connections.available);

console.log({ current: connections.current, available: connections.available, utilization: (utilization * 100).toFixed(1) + '%' });

// Alert if utilization high if (utilization > 0.8) { console.error('WARNING: Connection pool utilization > 80%'); // Send alert }

if (connections.available === 0) { console.error('CRITICAL: Connection pool exhausted'); // Send critical alert } } catch (error) { console.error('Monitoring error:', error); } }, 30000);

// Prometheus metrics // mongodb_connections{state="current"} // mongodb_connections{state="available"} // mongodb_connection_pool_utilization ```

MongoDB Connection Pool Checklist

CheckCommandExpected
Pool sizedriver configSufficient for load
ConnectionsserverStatus()current < max
Leakscode reviewConnections closed
Timeoutsdriver configReasonable values
Server limitmongod.conf> pool max
Long queriescurrentOpNone > 30s

Verify the Fix

```bash # After fixing connection pool issues

# 1. Check available connections mongo --eval "db.serverStatus().connections" // available > 0

# 2. Monitor pool utilization mongo --eval "db.serverStatus().connections" // current / (current + available) < 0.7

# 3. Test application connectivity node test_connection.js // Successfully connects

# 4. Run load test # Check connections stay within limits

# 5. Check for connection leaks over time # Monitor current connections shouldn't grow unbounded

# 6. Verify timeout handling # Connections returned to pool after idle time ```

  • [Fix MongoDB Connection Timeout](/articles/fix-mongodb-connection-timeout)
  • [Fix MongoDB Slow Query Performance](/articles/fix-mongodb-slow-query-performance)
  • [Fix MongoDB Replica Set Primary Not Found](/articles/fix-mongodb-replica-set-primary-not-found)