FATAL: sorry, too many clients already

PostgreSQL 'Too Many Clients Already' — Fix the Connection Limit

Postgres hit its max_connections cap and won't accept new clients. Raise the limit, kill idle sessions, and fix the app that's leaking connections.

Quick answer

Your Postgres server has hit max_connections and is refusing new clients. You need to disconnect idle sessions, raise the limit, and figure out why connections aren't being returned. This is rarely a Postgres bug — it's almost always an app or pooler issue.

What's actually happening

Postgres has a hard ceiling on simultaneous client connections. The default is 100. Every backend connection is a real OS process (not a thread), and each one eats a few hundred KB of memory plus has its own working memory. When you hit the cap, the server flatly refuses new logins with FATAL: sorry, too many clients already and that's it — no graceful degradation, no queue.

You'll see this most often in three situations. First, an application leaks connections — usually a Django/FastAPI/Express app with a connection pool that doesn't return connections on exceptions. Second, a midnight cron job or reporting script opens 50 connections in a burst and never closes them. Third, someone bumped a connection pool's max_size in dev without thinking about prod. We saw this exact thing at a client last year when their Celery workers went from 4 to 32 replicas overnight — every worker wanted 20 connections, and 640 requests hit a 100-connection Postgres.

Step-by-step fix

Step 1: Confirm you're actually hitting the limit

Open a terminal and check the current connection count. If you can't connect as a normal user, connect as postgres via local socket (the superuser slot is usually reserved).

psql -U postgres -c "SELECT count(*) FROM pg_stat_activity;"
psql -U postgres -c "SHOW max_connections;"

If count(*) is at or near max_connections, you've confirmed it. Don't guess — measure.

Step 2: See who's hogging connections

This query groups connections by state and user. Idle connections are the usual suspects.

SELECT usename, state, count(*)
FROM pg_stat_activity
GROUP BY usename, state
ORDER BY count DESC;

You'll usually see a wall of idle — meaning clients connected but aren't doing anything. That's the app not returning connections.

Step 3: Kill idle connections

Don't just kill everything — kill idles that have been sitting for a while. Anything idle for more than 10 minutes with no transaction in flight is safe to terminate.

SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle'
  AND state_change < now() - interval '10 minutes'
  AND pid <> pg_backend_pid();

After running that, you should see pg_stat_activity drop by dozens. New connections should start succeeding immediately. If they don't, verify with SELECT count(*) FROM pg_stat_activity; again.

Step 4: Raise max_connections (temporarily)

This buys you breathing room, not a fix. Set it in postgresql.conf:

max_connections = 200

Then reload — a full restart isn't required for this parameter on PostgreSQL 9.5+:

pg_ctl reload -D /var/lib/postgresql/data

Or from inside psql: SELECT pg_reload_conf();. After reload, SHOW max_connections; should return the new value. Verify by connecting a second time in a new terminal.

Be careful here. Each connection is a process. Going from 100 to 500 on a 2 GB RAM box is a great way to trigger the OOM killer and take down Postgres entirely. Rule of thumb: keep memory for connections under 25% of total RAM.

Step 5: Put PgBouncer in front

This is the real fix for most production setups. PgBouncer in transaction pooling mode lets 1000 app threads share 20 actual Postgres connections. Install it, then a minimal pgbouncer.ini:

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

[pgbouncer]
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 20
reserve_pool_size = 5

Point your app at PgBouncer's port (6432 by default) instead of 5432. Restart PgBouncer, then connect through it. You should see the same throughput with way fewer real backends — check pg_stat_activity and the count should be flat.

If the main fix doesn't hold

Find the leaking application

If connections climb back to the limit within an hour, you have a leak. This query shows the source IP and app name:

SELECT client_addr, application_name, count(*)
FROM pg_stat_activity
GROUP BY client_addr, application_name
ORDER BY count DESC;

If one IP is responsible for 80 connections, that's your culprit. Common causes: SQLAlchemy sessions not closed in a finally block, Node's pg pool missing pool.end(), or a Spring Boot HikariCP with maximumPoolSize set to something absurd like 100.

Set idle timeouts as a safety net

These two settings automatically kill connections that are sitting idle. They don't fix the leak, but they stop it from taking down your database at 3 AM.

idle_in_transaction_session_timeout = '5min'
idle_session_timeout = '30min'

idle_session_timeout requires PostgreSQL 14 or later. Reload the config and verify with SHOW idle_session_timeout;.

Check for stuck transactions

If you see idle in transaction states in pg_stat_activity, you've got an app that opened a transaction and forgot to commit. That's worse than a plain idle connection because it holds locks. Kill these first:

SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle in transaction'
  AND state_change < now() - interval '5 minutes';

Prevention

Don't just raise max_connections and walk away — that's how you end up with a 4 GB Postgres eating 30 GB of swap. Put PgBouncer (or pgpool-II) in front of Postgres from day one on anything with more than a handful of app instances. Set idle_session_timeout to 30 minutes so runaway clients get reaped automatically. And monitor pg_stat_activity — a simple alert when count(*) > 0.8 * max_connections gives you a warning before users start seeing errors. The connection limit error is almost never Postgres's fault. It's a signal that something upstream is holding connections it shouldn't.

Related Errors in Database Errors
SQL Server Query Execution Plan Cache Invalidation SQL Server Plan Cache Invalid: Fix in 3 Steps 1045 Fix MySQL ERROR 1045 Access Denied for User Error 2006: MySQL server has gone away phpMyAdmin Import Limit Exceeded: Real Fix 0XC019004D Fix STATUS_CANNOT_ABORT_TRANSACTIONS 0XC019004D in 5 Steps

Was this solution helpful?

EP
Erropedia Team
Tech Support Editors
The Erropedia editorial team researches and documents real-world tech errors from across Windows, Linux, macOS, networking, databases, cloud platforms, and more. Every solution is reviewed for accuracy and updated as software and systems evolve.