Home › Databases

FATAL: sorry, too many clients already — how to fix

psql: error: connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL:  sorry, too many clients already
FATAL: remaining connection slots are reserved for non-replication superuser connections

Quick fix: See who holds connections: SELECT usename, application_name, state, count(*) FROM pg_stat_activity GROUP BY 1,2,3 ORDER BY 4 DESC;. Kill idle ones with pg_terminate_backend, close connections in your code / cap pool size, put PgBouncer in front, and set idle_in_transaction_session_timeout. Raise max_connections only modestly (needs restart).

What it means

Every PostgreSQL connection is a separate server process. When the number of connections reaches max_connections (default 100), new ones are refused. A few slots are kept for superusers (superuser_reserved_connections, default 3), which is why you may see "remaining connection slots are reserved..." first.

Step 1: see who is connected

Connect as a superuser (the reserved slots let you in) and run:

SHOW max_connections;

SELECT usename, datname, application_name, client_addr, state, count(*)
FROM pg_stat_activity
WHERE backend_type = 'client backend'
GROUP BY 1,2,3,4,5
ORDER BY count(*) DESC;

Look for: hundreds of idle connections from one app (pool too large or leaked), or idle in transaction (code opened a transaction and never committed).

Step 2: free slots now

-- terminate connections idle for more than 10 minutes
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle'
  AND backend_type = 'client backend'
  AND state_change < now() - interval '10 minutes'
  AND pid <> pg_backend_pid();

Restarting the misbehaving application also releases its connections.

Cause 1: pool size × number of processes

Each app process gets its own pool. 4 servers × 8 workers × a pool of 10 = 320 connections. Size pools so the total stays under max_connections minus some headroom:

Cause 2: leaked connections

Connections opened but never closed — especially in error paths:

# Python: always use context managers
with psycopg.connect(dsn) as conn:
    with conn.cursor() as cur:
        cur.execute("SELECT 1")
// node-postgres: release clients from a pool
const client = await pool.connect();
try { await client.query('SELECT 1'); }
finally { client.release(); }

In serverless functions (Lambda, Vercel), create the pool outside the handler so it's reused, and use a pooler (RDS Proxy, PgBouncer, Supabase/Neon pooled URLs).

Cause 3: idle in transaction

Set server-side timeouts so stuck sessions get cleaned up:

ALTER SYSTEM SET idle_in_transaction_session_timeout = '5min';
ALTER SYSTEM SET idle_session_timeout = '30min';   -- PostgreSQL 14+
SELECT pg_reload_conf();

Fix: put PgBouncer in front

PgBouncer in transaction pool mode lets thousands of client connections share a few dozen server connections. Minimal pgbouncer.ini:

[databases]
mydb = host=127.0.0.1 port=5432 dbname=mydb

[pgbouncer]
listen_port = 6432
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
default_pool_size = 20
max_client_conn = 1000

Point your app at port 6432. (Transaction mode doesn't support session-level features like SET without LOCAL, advisory locks held across transactions, or — before PgBouncer 1.21 — named prepared statements.)

Raising max_connections

ALTER SYSTEM SET max_connections = 200;
sudo systemctl restart postgresql    # requires a restart, not just reload

Each connection costs memory (several MB plus work_mem per sort), so don't set this to thousands. On managed services (RDS, Cloud SQL, Azure) the limit is tied to instance size; change it via the parameter group.

Last updated 2026-11-03.