PostgreSQL 'too many clients' error — real cause and fix
Happens when you hit the max_connections limit. This is almost always a connection leak in your app, not a config problem.
You're running a web app, everything's fine for a few hours, then suddenly new queries start failing with FATAL: sorry, too many clients already. The app grinds to a halt. You check pg_stat_activity and see dozens of connections in idle state — they're not doing anything, just sitting there, eating up slots.
What's actually happening here
PostgreSQL has a hard limit on how many concurrent connections it accepts — default is 100. Every open connection, even idle ones, counts against that limit. Your app opened connections but never closed them properly. This is a connection leak. It's not a server resource issue (unless you're running a tiny VM with 256MB RAM), it's a code bug.
Why raising max_connections is the wrong fix
I see people bump max_connections to 500 or 1000 and call it done. That's a band-aid. Each connection consumes about 10MB of RAM for the backend process. More connections = more context switching = slower queries. The real fix is to stop leaking connections in your app.
Step-by-step fix
- Kill the idle connections to get back online
Connect as a superuser and run:
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle'
AND state_change < now() - interval '5 minutes'
AND backend_type = 'client backend'
AND pid != pg_backend_pid();
This kills connections idle for more than 5 minutes. Adjust the interval if you want to be more aggressive. This gets your app working again temporarily.
- Find the culprit application
Run this query to see which application is hogging connections:
SELECT application_name, count(*) as conn_count
FROM pg_stat_activity
WHERE backend_type = 'client backend'
GROUP BY application_name
ORDER BY conn_count DESC;
You'll likely see one app_name with 50+ connections. That's your leaky app.
- Check if it's a pooler or your app directly
If you use pgBouncer, the connections might be pooled — look atpgbouncer.databasesandpgbouncer.pools. But honestly, pgBouncer only pools if configured correctly. Most people hit this without a pooler.
- Fix the connection leak in your app
For Python (psycopg2):
# Wrong — missing close
cursor = conn.cursor()
cursor.execute('SELECT 1')
# Right — use context manager
with conn.cursor() as cursor:
cursor.execute('SELECT 1')
# conn autocommits or you close it after
conn.close()
For Node.js (pg):
// Wrong — never releasing the client
const client = new Client()
await client.connect()
// Right — release after use
const { rows } = await pool.query('SELECT 1')
// pool.query() handles acquire and release automatically
For Java (JDBC): Check your connection pool settings — set minimumIdle low (like 2) and connectionTimeout to 30 seconds. HikariCP defaults are usually sane, but if you see 100 connections from a single app, someone set maximumPoolSize too high.
- Set a sane connection limit per user
As a safety net, cap connections per role:
ALTER ROLE myapp CONNECTION LIMIT 20;
Now one app can't take down the whole server.
What to check if it still fails
- Are you using
psqlin a loop? I've seen dev scripts forget to exit. Add\qafter each command, or usepsql -cwhich auto-exits. - Is there a firewall or proxy holding connections open? TCP keepalive settings matter. Set
tcp_keepalives_idleto 60 seconds in postgresql.conf so stale connections get cleaned up faster. - Are you running a monitoring tool that opens many connections? Tools like pgHero or pgDash — set their
poolsize to 2, not 20. - If you're in Docker or Kubernetes, check that your connection pool lifecycle matches pod restarts. A long-lived pod that never recycles connections will accumulate them. Set
idleTimeoutto 10 minutes in your pooler.
Bottom line: Don't treat the symptom. Find the leak, fix it, and cap connections per role as insurance. Your database will run faster with 50 connections than 200.
Was this solution helpful?