PostgreSQL FATAL: sorry, too many clients already
sorry, too many clients already
Verified against PostgreSQL 17 docs (runtime-config-connection), pgbouncer docs (faq.html), Cloud provider best practices · Updated April 2026
> quick_fix
Your app is opening more connections than Postgres' max_connections setting allows (default 100). Install pgbouncer in front of Postgres to pool connections — this is the industry-standard fix, not raising max_connections.
# Check current setting
psql -c 'SHOW max_connections;'
# Quick raise (requires restart) — NOT recommended for real fix
# Edit postgresql.conf:
# max_connections = 500
# Real fix: use pgbouncer
sudo apt install pgbouncer
# Configure /etc/pgbouncer/pgbouncer.ini and /etc/pgbouncer/userlist.txt
# App connects to pgbouncer (port 6432) instead of Postgres (5432)What causes this error
Each Postgres connection spawns a backend process using ~10MB of RAM. max_connections caps how many backends can exist at once. When your app connection pool (or long-lived connections from idle clients) exceeds this, Postgres refuses new connections with this FATAL. Raising max_connections is a bandaid; real solution is connection pooling.
How to fix it
- 01
step 1
Check current connection count
See how many connections exist and which databases/users are consuming them.
SELECT datname, usename, state, COUNT(*) FROM pg_stat_activity GROUP BY datname, usename, state ORDER BY COUNT(*) DESC; - 02
step 2
Kill idle connections (temporary)
Buy yourself breathing room by killing idle-in-transaction connections that have been idle > 10 min.
SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'idle in transaction' AND state_change < now() - interval '10 minutes'; - 03
step 3
Install and configure pgbouncer
pgbouncer is a lightweight proxy that pools connections. Your app opens many connections to pgbouncer (cheap), which pools them to a small number of real Postgres connections.
- 04
step 4
Set transaction-level pooling in pgbouncer.ini
pool_mode = transaction is the best balance: each transaction gets a connection, then it's returned. Supports most app patterns except prepared statements.
# /etc/pgbouncer/pgbouncer.ini [databases] mydb = host=localhost port=5432 dbname=mydb [pgbouncer] pool_mode = transaction max_client_conn = 1000 default_pool_size = 20 - 05
step 5
Point your app at pgbouncer (port 6432)
Change DATABASE_URL to connect to pgbouncer port 6432 instead of Postgres 5432. max_client_conn = 1000 means you now support 1000 app connections with just 20 Postgres backends.
Frequently asked questions
Why not just raise max_connections to 1000?
Each connection uses ~10MB RAM. 1000 connections = 10GB RAM just for idle Postgres backends. Pgbouncer gives you the same concurrency at a fraction of the RAM.
Does pgbouncer support prepared statements?
Transaction pooling breaks prepared statements because the same connection isn't reused. Use session pooling if you need prepared statements, or use Postgres 17+ which has improved pgbouncer compatibility.