FATAL: remaining connection slots are reserved for non-replication superuser con

PostgreSQL FATAL: Remaining Connection Slots Are Reserved — Fix It Fast

You've hit max_connections and the reserved superuser slots are full. Here's how to get back in and stop it from happening again.

You're trying to connect to Postgres and it slaps you with FATAL: remaining connection slots are reserved for non-replication superuser connections. I know that error is infuriating — especially when it hits at 2am and your app is down. The short version: every connection slot is taken, and even the special slots Postgres keeps for superusers are gone. You either have too many connections or something is leaking them. Let's get you back in.

Cause 1: Your app (or a pooler) is leaking connections

Nine times out of ten, this is what's happening. An ORM opens connections and never closes them, or a connection pool is misconfigured and every request spawns a new session. I watched a Django service do this last year — every unhandled exception left a connection dangling, and within 40 minutes max_connections was toast.

First, get eyes on the damage. If you can still connect as a superuser (you might not be able to — we'll deal with that next), run this:

SELECT usename, application_name, client_addr, state, count(*)
FROM pg_stat_activity
GROUP BY 1,2,3,4
ORDER BY count DESC;

Look for a single application_name or usename hogging hundreds of slots. Idle-in-transaction states are the worst offenders — they hold locks and don't release until the client goes away.

The real fix is a connection pooler. If you're not running PgBouncer or pgpool-II in front of Postgres, do that today. Set it to pool_mode = transaction and cap default_pool_size well below max_connections. Your app talks to the pooler, the pooler multiplexes onto a small set of real Postgres connections. A typical setup: 200 app threads, 20 real DB connections, zero FATAL errors.

If you can't deploy a pooler right now, kill the offenders and buy yourself time. Careful — this terminates backends, so don't run it against a primary with active writes unless you mean it:

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

Cause 2: max_connections is set too low for your workload

Sometimes it's not a leak — you genuinely outgrew the default. Vanilla Postgres ships with max_connections = 100, and on a small RDS instance that's often 60-80 after the OS and reserved slots. A microservice fleet with 12 services each holding 10 connections chews through that instantly.

Check your current values:

SHOW max_connections;
SHOW superuser_reserved_connections;

superuser_reserved_connections defaults to 3. Those three slots are only usable by superusers and replication roles — and when the error says those are gone too, you're fully saturated.

You can raise max_connections in postgresql.conf:

max_connections = 200

Then pg_ctl reload (or SELECT pg_reload_conf();). A restart is safer if you also bumped shared_buffers. But here's my opinionated take: raising max_connections is a band-aid. Every connection costs roughly 5-10MB of memory plus a process (or backend slot). Push it to 500 on a 4GB box and you'll swap yourself to death. Fix the connection hygiene first, then bump the number as a cushion.

One thing people miss: reserved slots exist for a reason. When you're locked out, they're often your only way back in. Log in as the postgres OS user and connect via the Unix socket:

sudo -u postgres psql

That usually bypasses the TCP path and, if you're a superuser, uses one of the reserved slots. From there you can terminate backends and fix the real problem.

Cause 3: A backup, replica, or monitoring tool is eating slots

This one sneaks up on you. pg_dump on a big database holds a single connection for hours. A logical replication subscriber can spin up multiple workers. And monitoring tools — looking at you, Datadog and pgAdmin — love to open a session per dashboard widget.

Check the long-lived sessions specifically:

SELECT pid, usename, application_name, backend_start,
       now() - backend_start AS age, state, query
FROM pg_stat_activity
WHERE backend_start < now() - interval '1 hour'
ORDER BY age DESC;

If you see pg_dump, DBeaver, or a replica worker sitting for hours, that's your culprit. For monitoring tools, configure them to use a read replica or a dedicated connection pool. For pg_dump, prefer pg_dump -j 4 against a replica, or use a tool like pgBackRest that handles its own connection budget cleanly.

Replication deserves a special note. Physical replication slots are one connection per standby. Logical replication — introduced properly in PG 10 and refined since — uses a walsender per subscriber plus sync workers. On PG 14+, the new reserved_connections setting (renamed from superuser_reserved_connections behavior, now more flexible) lets you carve slots for specific roles. If you're running 14 or later, use it:

reserved_connections = 10  # slots for monitoring/admin roles

That stops a runaway app from ever starving your monitoring stack again.

Quick reference

CauseHow to spot itFix
Connection leak / no pooler pg_stat_activity shows one app with hundreds of idle sessions Deploy PgBouncer in transaction mode; kill idle backends
max_connections too low Many distinct apps, all legitimately connected Raise to 200 in postgresql.conf, reload, add RAM if needed
Backup / replica / monitoring hogging Long-lived sessions from pg_dump, DBeaver, walsender Move tooling to a replica; set reserved_connections (PG 14+)
Locked out entirely Can't even connect as superuser over TCP sudo -u postgres psql via Unix socket, then terminate backends

One last thing. After you've fixed this, go set an alert on SELECT count(*) FROM pg_stat_activity; at 80% of max_connections. This error never shows up on a healthy database — it always has a lead time of minutes to hours where you could've caught it. Get the alert in before it wakes you up again.

Related Errors in Database Errors
0X8004E031 CO_E_EXIT_TRANSACTION_SCOPE_NOT_CALLED (0x8004E031) Fix 0X80094006 Fix CERTSRV_E_SERVER_SUSPENDED (0x80094006) in 2 Steps 0X00001A99 Fix ERROR_STREAM_MINIVERSION_NOT_VALID (0x00001A99) on Windows MySQL Service Won't Start After Power Outage

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.