Your application logs are filling with FATAL: sorry, too many clients already, new requests that touch the database are failing, and healthy connections are being refused. The server itself is up, but it has run out of connection slots.
What this error means
PostgreSQL allows a fixed number of concurrent connections, set by max_connections. When every non-reserved slot is in use, the server rejects any further connection attempt with this FATAL message before the client can even authenticate. It is not a query error or a crash. The database is working, but it has no free slot to hand you.
Common causes
- An application or ORM connection pool sized larger than
max_connections, or many app instances each opening their own pool that sum past the limit. - Connection leaks in application code: connections checked out and never returned because of missing
close()calls or unhandled exceptions. idle in transactionsessions that opened aBEGINand never committed or rolled back, holding their slot (and often locks) indefinitely.- No connection pooler in front of Postgres, so short lived requests each open a fresh backend instead of reusing a warm one.
- A traffic spike, retry storm, or job backlog that briefly needs more concurrency than the server is configured for.
max_connectionsset low relative to real demand, or reduced by a managed service tier (RDS and Aurora derive a default from instance memory).
How to fix it
Work in order: get service back first, then find who is holding the slots, then fix the underlying cause.
- Get in through the reserved superuser slot. Regular roles are blocked, but
superuser_reserved_connections(default 3) keeps slots open for superusers. Connect as a superuser role.
psql -h your-host -U postgres -d your_database
- See how full you are and what the ceiling is.
SHOW max_connections;
SELECT count(*) AS total,
count(*) FILTER (WHERE state = 'idle in transaction') AS idle_in_txn,
count(*) FILTER (WHERE state = 'idle') AS idle
FROM pg_stat_activity;
- Identify the offenders. Look for sessions that are idle in transaction or have been idle a long time, grouped so you can see which application is responsible.
SELECT pid, usename, application_name, client_addr, state,
now() - state_change AS idle_for,
left(query, 60) AS last_query
FROM pg_stat_activity
WHERE state IN ('idle in transaction', 'idle')
ORDER BY state_change;
- Terminate the stuck sessions to free slots immediately.
pg_terminate_backendcloses the connection. Never terminate your own admin session or the internal background workers. Target the specific offenders.
-- Cancel any running statement first (gentler), then terminate if needed
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle in transaction'
AND now() - state_change > interval '5 minutes'
AND pid <> pg_backend_pid();
- Confirm slots have freed and normal traffic can connect again.
SELECT count(*) FROM pg_stat_activity;
- Now diagnose the real cause before it refills. If it is an app pool leak, restart or scale the offending service and check its pool configuration. If sessions keep going idle in transaction, set a timeout so the server self heals.
-- Self-managed: set globally then reload (no restart needed)
ALTER SYSTEM SET idle_in_transaction_session_timeout = '30s';
SELECT pg_reload_conf();
- Fix the architecture. If you have no pooler, put PgBouncer in front of Postgres in
transactionmode so hundreds of client connections share a small number of server backends. On RDS or Aurora, use RDS Proxy, and change limits through the DB parameter group (a static parameter change requires a reboot), notpostgresql.conf.
# pgbouncer.ini (excerpt)
[pgbouncer]
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 20
How to prevent it
- Put a connection pooler (PgBouncer, or RDS Proxy on AWS) between the app and the database, and keep total server backends well under
max_connections. - Size every application pool deliberately: sum of all app instance pool sizes plus admin headroom must stay below
max_connections. - Set
idle_in_transaction_session_timeoutand a sanestatement_timeoutso stuck sessions cannot camp on a slot. - Ensure code returns connections in a
finallyblock or uses the framework context manager, so exceptions do not leak connections. - Alert on
pg_stat_activitycount crossing roughly 80 percent ofmax_connections, and on anyidle in transactionolder than a minute. - Only raise
max_connectionsafter confirming memory headroom, since each connection consumes memory (work_memper sort, plus per backend overhead).
When to call a senior engineer
If terminating idle sessions frees slots but they refill within minutes, or you are tempted to raise max_connections on a memory constrained box under live load, stop. At that point you are guessing at a leak in application code or a pooler misconfiguration, and a wrong change (raising the limit into an out of memory event, or terminating the wrong backend mid-write) can turn a recoverable outage into data loss or a full crash. That is the moment to bring in someone who can trace the leak to its source and size the pool safely while the system stays up.
Related errors we fix
ERROR: could not extend file "base/16384/24576": No space left on device Fix this error → PostgreSQL could not resize shared memory segment ... : No space left on device Fix this error → PostgreSQL ERROR: deadlock detected Fix this error → PostgreSQL out of shared memory / increase max_locks_per_transaction Fix this error → Want a senior engineer to just fix it?
Paste this exact error into the form. A senior engineer replies within one business hour with what is likely wrong and a flat quote. Triage is free.
Book a fix