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:
- max_connections is typically 100 by default, possibly less if initdb found the kernel could not support it. It can only be changed with a server restart, and a standby must have the same or a higher value than its primary.
- superuser_reserved_connections defaults to 3. Once only those slots are free, only superusers may connect. With defaults, ordinary roles are refused at 97 connections.
- reserved_connections (PostgreSQL 16+, default 0) reserves extra slots for roles with privileges of
pg_use_reserved_connections, for example monitoring.
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:
- Hundreds of
idlesessions from the app servers. Each instance or worker keeps its own pool, and the total is more than the server allows. Ten pods with a pool of 20 each already need 200 slots. - Many
idle in transactionsessions. The code opens a transaction and does not finish it. These hold locks and block VACUUM too: see our article on idle in transaction. - Many
activesessions waiting on locks or I/O. The database really is slow, connections pile up while queries wait, and the app opens even more. Here the connection error is a symptom; fix the slow query or the lock. - One
client_addrorapplication_namewith far more sessions than the rest. A leak in one service, a cron job gone wild, or a BI tool.
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
- 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.
- 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.
- Limit roles and databases, not just the server. A
CONNECTION LIMITon a role or a database stops one service or one analyst from taking every slot. - Close forgotten sessions automatically.
idle_in_transaction_session_timeoutends 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 againstidle_session_timeouton connections that go through a pooler or other middleware, so set it per role, for interactive users. - 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
- "sorry, too many clients already" means all slots are taken; "remaining connection slots are reserved" means only the superuser reserve is left.
- Connect as a superuser and group
pg_stat_activityby user, app, address and state before you restart anything. - Free slots by ending forgotten
idle in transactionsessions withpg_terminate_backend. - max_connections defaults to about 100 and needs a restart to change; raising it tenfold is not a fix.
- The lasting fix is a pooler, sized app pools, per-role limits and idle timeouts.
- Keep applications off superuser accounts so the emergency reserve stays yours.