PgBouncer in transaction mode returns the backend connection to the pool after each transaction commits — allowing 5,000 app connections to share 100 backend connections. Session mode holds the backend connection for the entire client session (no multiplexing benefit). Statement mode breaks any application that uses multi-statement transactions or prepared statements. Transaction mode is the default recommendation unless your app uses session-level features (SET, advisory locks).
What to do next
Set default_pool_size = max_connections / 2 (leave headroom for direct admin connections). Monitor pgbouncer SHOW POOLS to watch pool saturation. Alert if cl_waiting > 0 for more than 5 seconds.
Use the PostgreSQL Connection Pool Calculator to run this on your own input.
Does PgBouncer support prepared statements in transaction mode?
Protocol-level prepared statements (PREPARE/EXECUTE) are not supported in transaction mode because they are session-scoped — a prepared statement prepared on one backend may not be available when the next transaction gets a different backend. Use server-side parameters or ORM query building instead. Named prepared statements work in session mode only.
How do I monitor PgBouncer pool exhaustion?
Connect to PgBouncer's admin console and run SHOW POOLS. The cl_waiting column shows clients waiting for a backend connection. If cl_waiting consistently exceeds zero, increase default_pool_size or optimize transaction duration. Also check sv_idle (idle backends in pool) — if always zero with cl_waiting > 0, you are pool-exhausted.