ESC
Type to search guides, tutorials, and reference documentation.
Verified by Garnet Grid

Database Connection Pool Management

Optimize database connection pools for performance and reliability. Covers pool sizing formulas, connection lifecycle, PgBouncer configuration, connection leak detection, and the patterns that prevent the most common cause of database outages.

A database connection is expensive — establishing a TCP connection, completing TLS handshake, authenticating, and allocating server-side memory takes 20-100ms. Connection pooling reuses established connections, amortizing this cost across thousands of queries. But pool misconfiguration is the most common cause of database-related outages: too few connections cause request queueing; too many overwhelm the database.


Connection Pool Sizing

PostgreSQL Connection Formula:

Max connections per database server:
  max_connections = (Available RAM - Shared Buffers - OS overhead) 
                    / per_connection_memory
  
  Typical values:
    Available RAM:        16 GB
    Shared Buffers:       4 GB
    OS overhead:          2 GB
    Per-connection memory: ~10 MB
    
    max_connections = (16 - 4 - 2) * 1024 / 10 = ~1000
    ⚠️ Practical limit: 200-500 (performance degrades at high counts)

Application pool size (per application instance):
  pool_size = (num_cores * 2) + disk_spindles
  
  For modern SSDs with 4-core application:
  pool_size = (4 * 2) + 1 = 9 (round to 10)
  
  Rule of thumb:
    CPU-bound queries: pool = core_count
    IO-bound queries: pool = core_count * 2-4
    Mixed workload: pool = core_count * 2

Total connections across all instances:
  total = pool_size * num_instances
  
  Example:
    pool_size = 10, instances = 20
    total = 200 connections
    
  If total > max_connections → use PgBouncer

PgBouncer Configuration

;; pgbouncer.ini — Connection pooler for PostgreSQL

[databases]
mydb = host=db-primary.internal port=5432 dbname=mydb

[pgbouncer]
; Pool mode: transaction is recommended for most workloads
pool_mode = transaction

; Connections from clients to PgBouncer
max_client_conn = 1000

; Connections from PgBouncer to PostgreSQL
default_pool_size = 20
min_pool_size = 5
reserve_pool_size = 5

; Timeouts
server_idle_timeout = 600        ; Close idle server connections after 10 min
client_idle_timeout = 0          ; Never close idle client connections
server_connect_timeout = 15      ; Fail fast if PostgreSQL is unreachable
query_wait_timeout = 120         ; Max wait time for a connection from pool

; Logging
log_connections = 1
log_disconnections = 1
log_pooler_errors = 1
stats_period = 60

Anti-Patterns

Anti-PatternConsequenceFix
No connection pooling20-100ms overhead per queryAlways use connection pooling
Pool too largeDatabase overwhelmed, OOM, context switchingSize pool based on formula, not guessing
Pool too smallRequests queue, timeouts, cascading failuresMonitor wait time, increase if consistently queueing
Connection leaksPool exhaustion, all requests blockedConnection leak detection, timeout idle connections
No connection validationStale connections cause query failuresEnable connection validation on checkout

Connection pool management is the intersection of application performance and database reliability. The pool is the pressure valve between your application’s desire for more connections and your database’s finite capacity. Size it correctly, monitor it continuously, and treat pool exhaustion as a critical alert.

Jakub Dimitri Rezayev
Jakub Dimitri Rezayev
Founder & Chief Architect • Garnet Grid Consulting

Jakub holds an M.S. in Customer Intelligence & Analytics and a B.S. in Finance & Computer Science from Pace University. With deep expertise spanning D365 F&O, Azure, Power BI, and AI/ML systems, he architects enterprise solutions that bridge legacy systems and modern technology — and has led multi-million dollar ERP implementations for Fortune 500 supply chains.

View Full Profile →