Incident Response

PostgreSQL "sorry, too many clients already": What to Do Now and Next

The app throws connection errors, the database looks half idle, and someone suggests setting max_connections to 1000. Before you restart anything, find out who is holding the slots. Here is the order we work in.

· 10 min read · AG Data Team

The PostgreSQL error "sorry, too many clients already" means every connection slot on the server is taken, so the server refuses the new connection. Usually the server is not overloaded at all: most of those connections are sitting idle. The quick fix is to free slots. The real fix is to stop the application from opening more connections than the database can use.

You will meet one of these two messages, often both:

FATAL:  sorry, too many clients already
FATAL:  remaining connection slots are reserved for roles with the SUPERUSER attribute

Both are FATAL with SQLSTATE 53300 (too_many_connections). The first one comes from proc.c when no free slot is left at all. The second comes from postinit.c when the only free slots are reserved; on PostgreSQL 16+ with reserved_connections set, a variant names the pg_use_reserved_connections role. Before PostgreSQL 16 the second message read "remaining connection slots are reserved for non-replication superuser connections". If you see a message that names a role or a database, "too many connections for role" or "too many connections for database", you hit a per-role or per-database CONNECTION LIMIT, not the server limit (miscinit.c).

How the limit actually works

From the connection settings documentation:

So the message tells you something. "Remaining slots are reserved" means ordinary roles ran out, but you, as a superuser, can still get in and look. "Too many clients already" means even the reserve is gone. From our experience, that often points to an application connecting as the postgres superuser, which eats the emergency reserve along with everything else.

Step 1: look before you restart

Connect as a superuser while the reserve still exists and see who holds the slots:

-- who holds the slots? (connect as a superuser: the reserve is for you)
SELECT usename, application_name, client_addr, state, count(*)
FROM pg_stat_activity
WHERE backend_type = 'client backend'
GROUP BY 1, 2, 3, 4
ORDER BY count(*) DESC
LIMIT 20;

SHOW max_connections;
SHOW superuser_reserved_connections;

The pattern usually jumps out in a minute:

Step 2: free slots safely

Restarting PostgreSQL frees all slots, but it also kills every running transaction and, if the cause is in the app, the slots fill up again within minutes. Ending the right sessions is gentler:

-- free slots now: end sessions idle in a transaction for over 10 minutes
SELECT pid, usename, application_name, now() - state_change AS idle_for,
       pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle in transaction'
  AND now() - state_change > interval '10 minutes';

pg_terminate_backend works for superusers, for roles with privileges of pg_signal_backend and for members of the session's own role, but only a superuser can terminate a superuser's session (server signaling functions). Each ended transaction is rolled back, so start with sessions that are clearly forgotten, not with active ones.

Do not jump to max_connections = 1000. Every connection is a separate server process, and PostgreSQL sizes some shared memory from max_connections. From our experience, a server with thousands of mostly idle connections usually gets slower under load, not faster, because too many active queries compete for the same CPU and locks. Raising the limit moderately is fine when the server has room. Raising it tenfold just moves the outage.

Step 3: fix the cause

  1. Put a pooler in front. PgBouncer in transaction mode lets thousands of client connections share a few dozen server connections. This is the standard fix for many app instances, serverless functions and PHP workers. Setup and pitfalls are in our PgBouncer guide.
  2. Size the app pools on purpose. Add up the maximum pool size across all instances, workers and cron jobs, including during a deploy when old and new pods run at the same time, and keep the total below max_connections minus the reserve.
  3. Limit roles and databases, not just the server. A CONNECTION LIMIT on a role or a database stops one service or one analyst from taking every slot.
  4. Close forgotten sessions automatically. idle_in_transaction_session_timeout ends sessions idle inside a transaction. idle_session_timeout (PostgreSQL 14+) ends idle sessions outside one. Both default to 0, which means off (client settings). The documentation warns against idle_session_timeout on connections that go through a pooler or other middleware, so set it per role, for interactive users.
  5. Keep a door open for yourself. Never let applications connect as a superuser. On PostgreSQL 16+, give monitoring its own reserve with reserved_connections, so alerts still work when ordinary roles are locked out.
-- cap the noisy neighbour instead of the whole server
ALTER ROLE reporting CONNECTION LIMIT 20;
ALTER DATABASE analytics CONNECTION LIMIT 50;

-- close forgotten sessions automatically, per role
ALTER ROLE app SET idle_in_transaction_session_timeout = '5min';
ALTER ROLE analyst SET idle_session_timeout = '30min';   -- PostgreSQL 14+

-- PostgreSQL 16+: a reserve for monitoring and ops roles
-- postgresql.conf: reserved_connections = 5   (restart needed)
GRANT pg_use_reserved_connections TO monitoring;

Finally, alert before the wall: track the number of client backends against max_connections and warn at around 80%. Then the next connection spike is a ticket, not an outage.

Key takeaways

PostgreSQL Connections max_connections Troubleshooting
Work with us

PostgreSQL refusing connections right now?

We help on an urgent basis: free connections safely, find the leak in the application or pool, and set up pooling, limits and alerts so it does not come back at the next traffic peak.

Get in touch More from the blog