Architecture & System Design › System Design Fundamentals · also in Relational Databases & SQL, Database Operations
Database Connection Pool
Reusing database connections, with tools like PgBouncer at scale.
Also known as: database connection pool, connection pool, db pool
A database connection pool is a managed set of reusable database connections shared by application threads: instead of opening (TCP + TLS + auth + session setup) per query, threads borrow a connection, use it, and return it. The pool bounds concurrency to what the database can actually serve while keeping hot connections ready.
100 app threads → pool of 20 connections → database (never overwhelmed)
Sizing is the craft: too few and threads queue (latency spikes); too many and the database thrashes (context switching, lock contention, memory per connection). The pool is also where timeouts, retries and prepared-statement reuse live — the operational surface of database access.
The classic mistakes:
- Pool per process, sized per process. Ten app instances × 50 connections = 500 against a database happy with 100. Size globally: divide the database’s budget across instances, or pool centrally (external pooler).
- Unbounded pools. “Grow as needed” grows until the database falls over — the pool’s job is to bound, applying backpressure to callers instead.
- Leaked checkouts. Borrowed-but-never-returned connections drain the pool until everything queues forever. Time out checkouts and alert on exhaustion.
- No statement reuse. Re-parsing every query wastes the planning the pool could amortise; prepare once per pooled connection where drivers support it.
- Transaction pinning. A thread holding a pooled connection across user think-time or external calls starves the pool. Keep transactions short; never hold across I/O.
- Ignoring pool metrics. Queue depth, wait time and utilisation predict outages before queries slow. Monitor the pool, not just the database.
- One pool for all workloads. Bulk imports sharing the OLTP pool starve interactive queries. Separate pools (or users) by workload class.
How to size it: start from the database’s comfortable connection count, divide by instances, separate workloads, monitor queueing — and treat the pool as a load-shedding boundary, not just a cache. See connection pooling for the general pattern.