// Data & Databases · 10
Connection Pooling
Reuse a small set of open connections instead of opening new ones.
How it fits together
- App instances uses / calls Database (direct)
- App instances uses / calls Connection pooler (pooled)
- Connection pooler uses / calls Database (fewer conns)
- App instances fails / error path Leaked connection (not closed)
- Leaked connection fails / error path Database (holds a slot)
Spot it
- Timeouts obtaining a connection from the pool
- The database hits its connection limit under load
- Scaling out the app makes the database worse
It costs
A bigger pool is not faster; too many connections slow the database down.
In code
// Pool size is part of the connection string, e.g. "...;Maximum Pool Size=20" for Npgsqlpublic sealed class OrderReader(string connectionString){ public async Task<int> CountOpenAsync(CancellationToken ct) { await using var connection = new NpgsqlConnection(connectionString); await connection.OpenAsync(ct); await using var command = new NpgsqlCommand( "SELECT COUNT(*) FROM orders WHERE status = 'open'", connection); return Convert.ToInt32(await command.ExecuteScalarAsync(ct)); }}Go deeperThe full explanation and what to ask for · 1 min readExpandCollapse
Opening a connection costs a TCP handshake, TLS and authentication, and in PostgreSQL a whole server process. Drivers pool connections per connection string automatically: closing or disposing returns the connection to the pool instead of closing it.
Exhaustion is usually a leak or a hold, not a pool that is too small: a connection never closed, a transaction left open across an HTTP call, or blocked threads holding connections. Raising the pool size hides the leak and moves the pressure onto the database.
Total connections are instances × pool size, and must fit under the server limit with headroom. With many instances or serverless, put a connection pooler in front; transaction mode multiplexes best but breaks session-level features such as SET, LISTEN and session advisory locks.
Ask for it
- maximum pool size
- pool exhaustion
- connection leak
- server connection limit
- connection pooler
- idle connection timeout
We get pool timeouts under load. Check for connection leaks (missing disposal, sync-over-async, transactions held across HTTP calls), size the maximum pool size so instances × pool fits under the server connection limit, and say whether we need a pooler (PgBouncer or pgpool).