Opening a database connection is not free. It involves a network handshake, authentication, and on some databases, allocating memory and backend processes on the server side — work that can take tens of milliseconds. Connection pooling keeps a set of already-open connections ready to reuse, so a request borrows one, uses it, and returns it instead of paying the setup cost every single time.
What changed in 2026
- Serverless and edge functions made connection pooling a much bigger deal, since a burst of thousands of short-lived function invocations can each try to open a direct database connection and exhaust the database server connection limit in seconds.
- External pooling proxies (PgBouncer, RDS Proxy, and similar tools) became close to a default requirement for serverless-to-Postgres or serverless-to-MySQL setups, rather than an optional optimization.
- Database-native pooling features improved, with several managed database providers now offering built-in poolers so teams do not have to run a separate pooling proxy themselves.
How a connection pool works
On application startup, the pool opens a fixed number of connections to the database and keeps them alive. When code needs to run a query, it checks out a connection from the pool, runs the query, and returns the connection when done, rather than closing it. If every connection is currently checked out, new requests wait (or fail, depending on configuration) until one frees up. The pool amortizes the expensive connect-and-authenticate step across many requests.
Sizing a connection pool
| Factor |
Effect on pool size |
| Number of app server instances |
Each instance typically has its own pool; total connections = instances x pool size |
| Database max_connections limit |
Sets a hard ceiling on total connections across all pools and clients combined |
| Query duration |
Longer-running queries hold connections longer, requiring a larger pool for the same throughput |
| Traffic burstiness |
Bursty traffic needs headroom above average load, or a queue/timeout strategy for spikes |
A common mistake is sizing each app instance pool as if it were the only consumer of the database, then scaling out the number of instances and blowing past the database connection limit without anyone changing a single pool setting.
Pooling modes
Most poolers offer a few modes: session pooling (a connection is dedicated to one client for the life of its session, closest to no pooling), transaction pooling (a connection is returned to the pool as soon as a transaction commits, allowing far higher reuse), and statement pooling (returned after every single statement, which breaks features that rely on session state like prepared statements or advisory locks). Transaction pooling is the most common choice for high-concurrency web workloads.
Common mistakes
- Running serverless functions with a direct, unpooled connection per invocation. This is the single most common way to exhaust a small database connection limit under real traffic.
- Setting pool size far higher than the database can actually support, which just moves the bottleneck from the app to the database without fixing anything.
- Using transaction-mode pooling with code that depends on session-level features, like prepared statements or session variables, causing subtle bugs that only appear under concurrency.
- Never closing idle connections. A pool that grows and never shrinks can hold connections the database needs for other clients, even during low-traffic periods.
FAQ
Do I need connection pooling for a small app?
Probably still yes if you deploy to serverless or expect any concurrent traffic. For a single long-running server process with low concurrency, the benefit is smaller but still generally worth the minimal setup cost.
What is the difference between an app-level pool and an external pooler like PgBouncer?
An app-level pool manages connections within one application process. An external pooler like PgBouncer sits between many application instances and the database, multiplexing many client connections onto fewer real database connections — useful when you have many app instances or serverless functions.
How does connection pooling relate to the N+1 query problem?
They are different problems that compound each other. See the N+1 query problem guide — a pool cannot fix an application making too many queries, but running out of pooled connections is often the visible symptom that surfaces an underlying N+1 issue.
What happens when the pool is exhausted?
Depending on configuration, new requests either wait in a queue for a connection to free up, or fail immediately with a connection timeout error. Both are better than the database itself refusing new connections outright.
Where to go next