The application is under load, connections are exhausted, and errors are appearing. The obvious fix is to raise the connection limit.
Do that and throughput frequently gets worse. The errors change from connection failures to slow queries, which is a less obvious problem and a harder one to diagnose.
What changed in 2026
- Serverless architectures made this acute. Function-per-request models opening connections independently exhausted limits routinely.
- Poolers became mandatory rather than advisable. Running without one stopped being viable at any real scale.
- Small-pool guidance held up. The counterintuitive finding that fewer connections serve more throughput continued to be confirmed.
- Pooler placement got attention. Where the pooler sits — in the application, as a sidecar, or as a separate service — became a considered decision.
Why more is worse
A database serving connections is not like a web server. Each connection consumes resources whether or not it is active, and active connections contend for the same finite hardware.
Fixed memory per connection. Every connection has associated memory for its state, buffers, and query workspace. Hundreds of connections consume that hundreds of times, and that memory is not available for caching data.
Contention. Concurrent connections compete for locks, buffers, and internal structures. Coordination overhead grows faster than linearly with concurrency.
CPU and I/O are finite. Twenty connections executing queries on eight cores are already oversubscribed. Two hundred do not get more work done — they get the same work done with far more context switching.
The result is a throughput curve that rises, peaks, and then falls. Past the peak, adding connections reduces total work completed while increasing every individual query's latency.
| Connections |
Throughput |
Latency |
| Very few |
Below capacity |
Low |
| Near optimal |
Peak |
Low |
| Well above optimal |
Falling |
Rising sharply |
| Far above optimal |
Poor |
Very high |
Pool sizing
The common error is sizing the pool to application concurrency: a thousand concurrent requests, so a thousand connections.
The right basis is what the database can serve well, which is a much smaller number related to available cores and the storage's ability to service concurrent I/O. It is frequently in the low tens even for substantial hardware.
Requests beyond that queue at the pool. That sounds bad and is far better than the alternative: a queued request waits and then executes quickly, whereas an admitted request in an oversubscribed database executes slowly and makes everyone else slower too.
Queueing at the pool converts contention into an orderly wait, which is the whole point — see connection pooling explained.
Find the number empirically. Load test at increasing pool sizes and watch where throughput peaks; that is your size, and it is usually smaller than expected.
Idle connections are not free
An idle connection still holds its memory allocation. A large pool of mostly-idle connections consumes memory that would otherwise cache data.
Worse, an idle connection inside a transaction holds locks and blocks cleanup across the database — the single most damaging connection state, per MVCC explained. Bounding it with an idle-in-transaction timeout matters more than the connection count itself.
The serverless case deserves specific mention: a platform scaling to hundreds of concurrent function instances, each opening its own connection, exhausts limits immediately. A pooler between them is not optional there — it is what makes the architecture work at all.
Common mistakes
- Raising the limit to fix exhaustion. Trades one problem for a worse one.
- Sizing the pool to application concurrency. Wrong basis entirely.
- No pooler in a serverless architecture. Guaranteed exhaustion.
- Ignoring idle-in-transaction connections. The most damaging state.
- Not load testing pool size. The optimum is smaller than intuition suggests.
- Several application instances each with a large pool. The total is what the database sees.
- Forgetting reserved connections. Leave headroom for administrative access during an incident.
FAQ
How do I find the right pool size?
Load test at several sizes and find where throughput peaks. Start lower than you expect; the peak is frequently at a surprisingly small number.
What if requests queue at the pool?
That is the design working. A brief queue with fast execution beats immediate admission with slow execution. Monitor queue wait time, and if it is consistently high you need more database capacity rather than more connections.
Does pooling mode matter?
Considerably. Transaction-mode pooling multiplexes far more effectively and breaks session-scoped features — see connection pooling explained.
Should I reserve connections?
Yes — keep headroom so an administrator can connect during an incident. A database at its connection limit that you cannot log into is a much worse incident.
Where to go next
For pooling mechanics and modes, read connection pooling explained. For bounding idle transactions, statement timeouts, and for the cleanup they block, autovacuum tuning.