Connection pooling is a technique for reusing a set of pre-established database (or network) connections rather than creating and destroying a new connection for every request. It dramatically reduces latency and resource overhead in applications that talk to databases or external services at high frequency.
A connection pool is a cache of reusable connections maintained by a pool manager. When your application needs a connection, it borrows one from the pool; when done, the connection is returned to the pool instead of being closed. This avoids the expensive TCP handshake, authentication, and session setup that would otherwise happen on every request.
Opening a raw database connection can take tens to hundreds of milliseconds and consume significant CPU and memory on both the client and the database server. Without pooling, a spike in traffic can exhaust database connection limits and cause cascading failures. Pooling smooths out demand, keeps latency predictable, and lets a single database server handle far more concurrent application threads than it has native connections.
At startup, the pool manager opens a configurable minimum number of connections (min pool size) and holds them open. Incoming requests acquire an idle connection; if none is available the requester either waits in a queue or a new connection is created up to the maximum pool size. Health-check queries and idle timeouts let the manager silently replace stale or broken connections without the application noticing.
The most important knobs are min connections (warm connections always ready), max connections (hard ceiling to protect the database), connection timeout (how long a requester waits before receiving an error), and idle timeout (how long an unused connection stays open). Setting max too high shifts the bottleneck to the database; setting it too low causes queue buildup and timeouts under load.
A connection leak occurs when application code acquires a connection but never returns it — typically because an exception bypassed the cleanup path. Over time, all connections are held permanently and new requests block forever. Always release connections in a finally block or use a language construct like Python's context manager or Java's try-with-resources to guarantee return even on error.
Size your pool based on actual database server capacity, not application thread count — a common rule of thumb is (number of CPU cores × 2) + effective spindle count for PostgreSQL. Use application-level connection pool libraries (HikariCP, pgBouncer, SQLAlchemy pool) rather than rolling your own. Monitor pool wait time and checkout duration as key health metrics; a rising wait time is an early warning of saturation or leaks.
© RM Full Stack & AI Engineer · All guides · Roadmaps · Open the app