Skip to main content
SDMastery
intermediate9 min readUpdated 2026-06-08

Connection Pooling

Connection pooling reuses a pool of pre-established database connections instead of creating new ones per request, dramatically reducing latency and.

Quick answer: Connection Pooling

Connection Pooling is covered here as a practical system design concept. Connection pooling reuses a pool of pre-established database connections instead of creating new ones per request, dramatically reducing latency and. Use it to understand the Databases idea, where it appears in production systems, and how to discuss it clearly in interviews.

Focus on the problem being solved, the main design choice, the failure mode, and the tradeoff you would defend in front of a senior engineer. This page is part of the DosiBridge system design knowledge graph, so it links related concepts, interview problems, tradeoffs, and references instead of leaving the topic isolated.

Diagram showing the key components and data flow in a Connection Pooling system design
High-level overview of Connection Pooling
Connection Pooling

Connection pooling maintains a cache of reusable database connections so that applications don't pay the overhead of establishing a new TCP connection, performing a TLS handshake, and authenticating for every query. Without pooling, a web server handling 1,000 concurrent requests would need 1,000 simultaneous database connections — far exceeding what most databases can handle. Connection pools like PgBouncer, HikariCP, and built-in ADO.NET pooling solve this by multiplexing many application requests across a smaller number of persistent connections.

AspectDetails
What it isA technique that maintains a pool of pre-established database connections, lending them to application threads and returning them after use
When to useAny application that makes database queries — connection pooling should be enabled by default in virtually every production system
When NOT to useLong-running batch jobs that hold connections for minutes or hours — these starve the pool; use a separate pool or direct connections instead
Real-world exampleHeroku uses PgBouncer in front of PostgreSQL to allow thousands of dynos to share a limited number of database connections efficiently
Interview tipKnow the numbers — creating a new PostgreSQL connection takes 50-100ms while borrowing from a pool takes under 1ms; this 100x difference matters at scale
Common mistakeSetting the pool size too large, which overwhelms the database with connections, or too small, which causes application threads to block waiting for a connection
Key tradeoffLarger pools handle more concurrency but consume more database memory and can cause contention; smaller pools limit concurrency but keep the database healthy

Why This Matters

Connection pooling is critical because database connections are expensive resources. Each connection consumes memory on both the application server and the database server (PostgreSQL uses ~10MB per connection). Creating a new connection involves DNS resolution, TCP handshake, TLS negotiation, and authentication — typically 50-100ms. At scale, an application handling thousands of requests per second would exhaust the database's connection limit within seconds without pooling. Understanding pool sizing, timeout configuration, and health checking is essential for building reliable, performant systems.

System architecture diagram for Connection Pooling showing how services, databases, and caches connect
System architecture for Connection Pooling

The Building Blocks

  • Pool Initialization: On startup, the pool creates a minimum number of connections (minIdle). These are ready immediately, eliminating cold-start latency for the first requests.
  • Borrow & Return: When a thread needs a connection, it borrows one from the pool. After the query completes, the connection is returned (not closed), making it available for the next thread.
  • Connection Validation: Pools periodically test idle connections with lightweight queries (like SELECT 1) and discard broken ones, ensuring application code never receives a stale or dead connection.
  • Pool Sizing: The optimal pool size depends on the number of CPU cores and disk spindles — HikariCP's formula is connections = (cores * 2) + effective_spindle_count, typically 10-20 for most workloads.
  • External Poolers: Dedicated pooling proxies like PgBouncer and ProxySQL sit between the application and database, providing connection multiplexing at the infrastructure level rather than per-application.

Under the Hood

A connection pool maintains a bounded collection of database connections in different states: idle (available), in-use (borrowed by a thread), and being-validated (health check in progress). When a thread requests a connection, the pool checks for available idle connections. If one exists, it's returned immediately (sub-millisecond). If none are available and the pool hasn't reached maxSize, a new connection is created. If the pool is at capacity, the thread blocks until a connection is returned or a timeout expires.

Step-by-step diagram showing how Connection Pooling processes a request from start to finish
How Connection Pooling works step by step

The pool tracks connection age and idle time. Connections that exceed maxLifetime are closed and replaced, preventing issues from server-side timeouts, memory leaks, or network changes. Idle connections exceeding idleTimeout are pruned to free database resources during low-traffic periods. Health checks — either test-on-borrow (adds latency) or background validation (no request-path overhead) — ensure connections are functional.

External poolers like PgBouncer operate in three modes: session (one pool connection per client session), transaction (connections returned after each transaction — most common), and statement (connections returned after each statement). Transaction mode is the most efficient, multiplexing thousands of client connections across dozens of database connections. However, it doesn't support session-level features like prepared statements or SET commands, which can surprise developers.

How Companies Actually Do This

Heroku PgBouncer runs as a buildpack on every Heroku dyno, allowing thousands of dynos to share a single PostgreSQL instance's limited connection slots — without it, popular apps would exhaust the 500-connection limit instantly.

Comparison table for Connection Pooling contrasting approaches, tradeoffs, and when to use each
Comparing key aspects of Connection Pooling

Instagram Uses connection pooling extensively in their Django application layer to handle hundreds of thousands of queries per second against PostgreSQL, with careful pool tuning to prevent thundering herd issues during traffic spikes.

Shopify Uses ProxySQL as a connection pooler and query router in front of MySQL, multiplexing connections from thousands of application pods and routing reads to replicas and writes to the primary.

Common Pitfalls

  1. Setting pool size equal to max concurrent requests — if you have 200 threads and a pool of 200, the database gets 200 connections per app instance; with 10 instances that's 2,000 connections, likely crashing the database
  2. Not configuring connection timeouts — without a connectionTimeout, threads block indefinitely waiting for a pool connection during traffic spikes, causing cascading failures
  3. Leaking connections by not closing them in finally blocks — if exception handling misses a return path, connections are never returned to the pool, eventually exhausting it
Data flow diagram for Connection Pooling showing how requests and responses move through the system
Data flow through Connection Pooling

Interview Questions Worth Practicing

  1. How would you determine the optimal connection pool size for an application handling 10,000 requests per second?
  2. What happens when all connections in a pool are in use and a new request arrives? How would you handle this?
  3. Explain the difference between application-level connection pooling and an external pooler like PgBouncer. When would you use each?

The Tradeoffs

  • Pool Size vs Database Load: Larger pools give applications more concurrent database access but consume more memory and CPU on the database server
  • Validation Overhead vs Reliability: Testing connections on every borrow adds ~1ms latency but guarantees working connections; background validation is faster but may miss recently broken connections
  • Session vs Transaction Pooling: Transaction pooling multiplexes connections most efficiently but breaks session-level features like prepared statements and temporary tables
Component diagram for Connection Pooling showing each building block and its responsibility
Key components of Connection Pooling

How to Explain This in an Interview

Here is how I would explain Connection Pooling in a system design interview:

Explain that database connections are expensive to create (TCP + TLS + auth = ~100ms) and expensive to hold (each consumes ~10MB on the database server). Connection pooling solves both by maintaining a cache of pre-established connections that threads borrow and return. Walk through the lifecycle: the pool initializes with minIdle connections, threads borrow available ones or wait if the pool is exhausted, and connections are validated periodically to discard dead ones. For pool sizing, cite the formula: connections = (CPU cores * 2) + spindles, which means most databases perform best with 10-30 connections per instance. Mention external poolers like PgBouncer for environments where many application instances share a single database. Close with the key pitfall: connection leaks from missing finally blocks silently exhaust the pool over time.

Interview preparation checklist for Connection Pooling with key points to mention and mistakes to avoid
Interview tips for Connection Pooling

Original DosiBridge notes for Connection Pooling

This section is written specifically for this page, not copied from a general system-design checklist. The useful way to study Connection Pooling is to connect the concept to a production service where growth exposes the first weak assumption in the original design. That framing changes the design discussion from definitions to operating choices.

What makes this topic distinct

  • Query Shape: For Connection Pooling, decide the query shape before choosing tools; otherwise the design looks clean but fails when connection changes.
  • Write Amplification: For Connection Pooling, decide the write amplification before choosing tools; otherwise the design looks clean but fails when pooling changes.
  • Replication Lag: For Connection Pooling, decide the replication lag before choosing tools; otherwise the design looks clean but fails when connection changes.
  • Migration Safety: For Connection Pooling, decide the migration safety before choosing tools; otherwise the design looks clean but fails when pooling changes.
  • Data Ownership: For Connection Pooling, decide the data ownership before choosing tools; otherwise the design looks clean but fails when connection changes.

Production review question

If a team adopts Connection Pooling, what observable signal proves it helped instead of only making the architecture diagram more fashionable?

Practical metric to track

Track connection-pooling health as a named dashboard or review item: combine one user-facing metric, one saturation metric, and one correctness metric. For Connection Pooling, this keeps the discussion grounded in behavior that can be measured after deployment instead of generic advice that sounds good in an interview but never gets verified.