53300
PostgreSQLFATALNotableToo Many ConnectionsHIGH confidence

remaining connection slots are reserved for non-replication superuser connections

What this means

The connection limit has been reached. Postgres reserves a small number of connection slots exclusively for superusers (controlled by superuser_reserved_connections, default 3). Non-superuser clients receive this error when max_connections minus the reserved slots are all occupied.

Why it happens
  1. 1Application connection pool misconfiguration: too many connections created relative to max_connections
  2. 2Connection leak: application code opens connections but does not close them
  3. 3max_connections is set too low for the workload
  4. 4Idle connections accumulating (idle_in_transaction sessions not timing out)
How to reproduce

A non-superuser connection attempt when all non-reserved slots are occupied.

trigger — this will error
trigger — this will error
-- Check current connection state:
SELECT count(*) AS total,
       sum(CASE WHEN state = 'idle' THEN 1 ELSE 0 END) AS idle,
       sum(CASE WHEN state = 'idle in transaction' THEN 1 ELSE 0 END) AS idle_in_txn
FROM pg_stat_activity
WHERE pid <> pg_backend_pid();

SHOW max_connections;
SHOW superuser_reserved_connections;

expected output

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

Fix 1

Use a connection pooler (PgBouncer)

WHEN When many application processes each open their own connections to Postgres.

Use a connection pooler (PgBouncer)
-- PgBouncer sits between the application and Postgres.
-- Configure pool_size in pgbouncer.ini to limit Postgres connections.
-- Applications connect to PgBouncer (e.g. port 6432) instead of Postgres directly.

-- Verify pooler is working:
SELECT count(*) FROM pg_stat_activity; -- should be low even under high app load

Why this works

PgBouncer multiplexes many application connections onto a small number of real Postgres backend connections. In transaction pooling mode, a Postgres connection is only held for the duration of a transaction, then returned to the pool. This can reduce required Postgres connections by 10-50x.

Fix 2

Terminate idle connections and tune timeouts

WHEN As an immediate relief measure to free connections.

Terminate idle connections and tune timeouts
-- Terminate idle connections older than 10 minutes:
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle'
  AND query_start < NOW() - INTERVAL '10 minutes'
  AND pid <> pg_backend_pid();

-- Prevent future accumulation:
ALTER SYSTEM SET idle_in_transaction_session_timeout = '5min';
SELECT pg_reload_conf();

Why this works

pg_terminate_backend() sends SIGTERM to idle backends, freeing their connection slots immediately. idle_in_transaction_session_timeout automatically terminates backends stuck in an open transaction after the specified interval, preventing slot leakage.

What not to do

Increase max_connections indefinitely to accommodate all connections

Each Postgres connection uses ~5-10MB of shared memory; very high max_connections increases memory pressure and can degrade performance due to lock contention in shared memory.

Version notes
Postgres 14+

Connection slot reservation for replication connections is now controlled separately by reserved_connections (for replication workers) in addition to superuser_reserved_connections.

Sources
Official documentation ↗

src/backend/postmaster/postmaster.c — ConnCreate()

Connection ConfigurationPgBouncer

Content generated with AI assistance and reviewed for accuracy. Found an error? hello@errcodes.dev

← All PostgreSQL errors