Skip to content
Optimal Lab

Databases · interactive

Connection pooling

Every Postgres connection is a process using memory, so the database caps them with max_connections. A pooler sits in front with two more limits: how many app connections it accepts, and how many real connections its pool opens. Pick a platform, then change any number and see which limit breaks first.

8 instances × 10 connections → PgBouncer

1 · App connections into PgBouncer (client limit 100)

accepted 80

2 · Server connections the app needs (pool size 20, one per connected client)

running 20queued 60pool size

3 · Postgres max_connections = 100

reserved 3other direct 5PgBouncer pool 20free 72
Queries failing
75%
Wait per query
120 s, then error
Queued
60
Limit hit
pool size

What you'd see

  • app: Queries hang, then fail after 120 s: query_wait_timeout (default 120 s)
; pgbouncer.ini
pool_mode = session
max_client_conn = 100
default_pool_size = 20

-- postgresql.conf
max_connections = 100

80 connections each hold a server connection for their whole session, but the pool has 20. The rest wait until the timeout, then fail.

Platform

Defaults: max_client_conn = 100, default_pool_size = 20, pool_mode = session. The pool is per user + database pair.

Pool mode

Database and pooler limits

Reserved slotssuperuser_reserved_connections = 3 (Postgres default)3

Your app

Driver or ORM

new Pool(): max defaults to 10.

  1. 1

  2. 2

  3. 3

    How many real connections the pooler opens per user + database. In session mode each client keeps one for its whole session, so the pool must be as big as the client count. In transaction mode only in-flight transactions need one.

    Failure: queries queue, then time out.

  4. 4