How to fix FATAL: remaining connection slots are reserved for non-replication superuser connections in PostgreSQL

PostgreSQLINTERMEDIATEHIGHUpdated May 28, 2026· 337 views

PostgreSQL rejects new client connections because all non-reserved slots are in use and the rest are held for superusers. Fix by freeing idle connections, adding pooling, and raising max_connections.

Quick fix

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

-- View current connection counts
SELECT datname, count(*) FROM pg_stat_activity GROUP BY datname;

-- List all active connections with details
SELECT pid, usename, application_name, state, query_start 
FROM pg_stat_activity 
ORDER BY query_start DESC;

-- Check max_connections and superuser_reserved_connections settings
SHOW max_connections;
SHOW superuser_reserved_connections;
  1. Check current connection usage
  2. Terminate idle or long-running connections
  3. Persist a higher max_connections with ALTER SYSTEM (requires restart)
  4. Set max_connections in postgresql.conf
postgresql — error
-- View current connection counts
SELECT datname, count(*) FROM pg_stat_activity GROUP BY datname;
-- List all active connections with details
SELECT pid, usename, application_name, state, query_start
FROM pg_stat_activity
ORDER BY query_start DESC;
-- Check max_connections and superuser_reserved_connections settings
SHOW max_connections;
SHOW superuser_reserved_connections;
FATAL: remaining connection slots are reserved for non-replication superuser connections

What this error means

This PostgreSQL error occurs when the server has exhausted all available connection slots allocated for regular (non-superuser) clients. PostgreSQL reserves a portion of its maximum connections exclusively for superusers and replication roles via the superuser_reserved_connections parameter (default 3 slots). When all non-reserved slots are in use, new client connections are rejected with this FATAL error. The actual limit for regular clients is calculated as: max_connections (default 100) minus superuser_reserved_connections (default 3) minus rds.rds_superuser_reserved_connections (AWS RDS specific, default 2). This safety mechanism ensures database administrators can always connect even when the database appears full, but it prevents regular applications from connecting when capacity is reached.

Typical symptoms

  • Applications receive "FATAL: remaining connection slots are reserved" error when attempting to connect
  • Database appears responsive but rejects new non-superuser connections
  • Superusers can still connect and perform maintenance
  • Connection pooling or application connection attempts fail repeatedly
  • Monitoring dashboards show connections are at or near max_connections limit
  • Error appears after period of normal operation, coinciding with increased load
  • AWS RDS shows connection limit reached with fewer connections than expected

Common causes

  1. max_connections parameter set too low for application load (default 100 connections)
  2. Application connection leaks: connections opened but never properly closed
  3. Connection pooling not configured or pool size too large relative to max_connections
  4. Slow or blocked queries consuming connections that cannot complete and release slots
  5. Idle connections holding slots due to high statement_timeout or client timeout settings
  6. Traffic spikes or load increases exceeding available connection capacity
  7. AWS RDS: additional reserved connections for RDS management reducing user-available slots
  8. Connections used by background processes or replicas consuming slots

How to fix "FATAL: remaining connection slots are reserved for non-replication superuser connections"

1Check current connection usage

Connect as a superuser and examine active connections:

sql
-- View current connection counts
SELECT datname, count(*) FROM pg_stat_activity GROUP BY datname;

-- List all active connections with details
SELECT pid, usename, application_name, state, query_start 
FROM pg_stat_activity 
ORDER BY query_start DESC;

-- Check max_connections and superuser_reserved_connections settings
SHOW max_connections;
SHOW superuser_reserved_connections;

Identify how many connections are active and what percentage of max_connections is in use.

2Terminate idle or long-running connections

Free up connection slots by terminating idle or problematic connections:

sql
-- Find idle connections (in transaction but doing nothing)
SELECT pid, usename, application_name, state, state_change 
FROM pg_stat_activity 
WHERE state = 'idle in transaction' 
AND query_start < now() - interval '10 minutes';

-- Terminate a specific connection
SELECT pg_terminate_backend(pid) FROM pg_stat_activity 
WHERE pid = <PID>;

-- Terminate all idle connections from a specific application
SELECT pg_terminate_backend(pid) FROM pg_stat_activity 
WHERE application_name = 'app_name' AND state = 'idle';

-- Terminate connections idle for more than 30 minutes
SELECT pg_terminate_backend(pid) FROM pg_stat_activity 
WHERE state = 'idle' 
AND state_change < now() - interval '30 minutes'
AND pid <> pg_backend_pid();

This provides immediate relief by reclaiming slots held by leaked or stuck sessions, buying time while you apply a permanent fix.

3Persist a higher max_connections with ALTER SYSTEM (requires restart)

You can set max_connections without hand-editing config files by using ALTER SYSTEM, which writes the value to postgresql.auto.conf:

sql
ALTER SYSTEM SET max_connections = 200;

Important: max_connections is a postmaster-level (context = postmaster) parameter. Unlike many runtime settings, it does not take effect with `SELECT pg_reload_conf();` — that command only reloads parameters that support reload, and max_connections is not one of them. The new value is applied only after a full server restart, because PostgreSQL allocates shared memory for all possible connections at startup.

Confirm the parameter still requires a restart and verify the pending value:

sql
-- 'postmaster' context means a restart is required
SELECT name, setting, context, pending_restart
FROM pg_settings
WHERE name = 'max_connections';

Then restart PostgreSQL during a maintenance window:

bash
# Linux (systemd)
sudo systemctl restart postgresql

# macOS Homebrew
brew services restart postgresql

# Or using pg_ctl
pg_ctl -D /path/to/data/directory restart

Each connection reserves memory (work_mem-related buffers, etc.), so before raising this value, verify the host has sufficient RAM. On managed services (AWS RDS, Cloud SQL, Azure), change max_connections via the provider's parameter group / flags rather than ALTER SYSTEM, and note many managed services derive it from instance memory by default.

4Set max_connections in postgresql.conf

If you prefer editing the main config file instead of using ALTER SYSTEM, locate postgresql.conf:

bash
# Find postgresql.conf location
psql -U postgres -c "SHOW config_file;"

# On Linux/macOS it's typically:
# /etc/postgresql/*/main/postgresql.conf
# /var/lib/pgsql/data/postgresql.conf
# /usr/local/var/postgres/postgresql.conf (macOS Homebrew)

Edit the file and locate or add the max_connections parameter:

ini
# Original (default)
max_connections = 100

# Increase based on load
max_connections = 300

Choose a value based on your workload. As a guideline: web apps typically use 50-200, high-concurrency apps 200-500, and data warehouse environments may exceed 1000. Because max_connections requires a restart to take effect, apply it during a maintenance window:

bash
# Linux
sudo systemctl restart postgresql

# macOS Homebrew
brew services restart postgresql

# Or using pg_ctl
pg_ctl -D /path/to/data/directory restart

Note: a value set in postgresql.auto.conf (via ALTER SYSTEM) overrides the same setting in postgresql.conf, so pick one approach to avoid confusion.

5Implement connection pooling with PgBouncer

Raising max_connections has limits; the more scalable fix is to put a pooler in front of PostgreSQL. Deploy PgBouncer to multiplex many client connections into fewer database connections:

bash
# Install PgBouncer
sudo apt install pgbouncer  # Debian/Ubuntu
brew install pgbouncer       # macOS

Edit /etc/pgbouncer/pgbouncer.ini (or /usr/local/etc/pgbouncer.ini on macOS):

ini
[databases]
mydb = host=localhost port=5432 dbname=mydb

[pgbouncer]
listen_port = 6432
listen_addr = 127.0.0.1
mode = transaction
max_client_conn = 1000
default_pool_size = 25
min_pool_size = 5

Applications connect to PgBouncer on port 6432 instead of PostgreSQL directly. PgBouncer maintains a small pool of connections to PostgreSQL and reuses them across many client connections. This dramatically reduces the actual database connections needed.

6Fix application connection leaks

Review application code to ensure connections are properly closed. Connection leaks occur when:

Python (psycopg2):

python
# BAD: Connection never closed
conn = psycopg2.connect("dbname=mydb")
cursor = conn.cursor()
# ... query code ...
# Missing: conn.close()

# GOOD: Use context manager
import psycopg2
with psycopg2.connect("dbname=mydb") as conn:
    with conn.cursor() as cursor:
        # ... query code ...
        # Connection automatically closed

Node.js (pg):

javascript
// BAD: Connection not released
const client = new Client();
await client.connect();
const res = await client.query('SELECT ...');
// Missing: await client.end();

// GOOD: Use pools with automatic release
const pool = new Pool();
const res = await pool.query('SELECT ...');
// Connection automatically returned to pool

Ruby (ActiveRecord):

ruby
# GOOD: Connections managed automatically
ActiveRecord::Base.connection_pool.with_connection do |conn|
  conn.execute('SELECT ...')  # Released when block exits
end

Always use connection pools or context managers to ensure connections are released.

7Set idle_in_transaction_session_timeout

Set a timeout to automatically disconnect clients that leave transactions open without activity:

sql
-- Set globally (requires superuser); this parameter supports reload
ALTER SYSTEM SET idle_in_transaction_session_timeout = '10min';
SELECT pg_reload_conf();

-- Or in postgresql.conf
idle_in_transaction_session_timeout = 600000  # 10 minutes in milliseconds

Unlike max_connections, this setting takes effect with a configuration reload (no restart needed). It prevents idle transactions from holding connection slots indefinitely. Affected sessions are terminated after the timeout, forcing applications to reconnect. Common values range from 5-30 minutes depending on your application patterns.

8Monitor connection usage with dashboards

Set up ongoing monitoring to prevent future exhaustion:

sql
-- Create a monitoring query to check connection health
CREATE OR REPLACE FUNCTION check_connection_health() RETURNS TABLE (
  total_connections bigint,
  active_connections bigint,
  idle_connections bigint,
  max_allowed bigint,
  reserved_slots bigint,
  available_slots bigint,
  usage_percent numeric
) AS $$
SELECT
  (SELECT count(*) FROM pg_stat_activity) as total_connections,
  (SELECT count(*) FROM pg_stat_activity WHERE state != 'idle') as active_connections,
  (SELECT count(*) FROM pg_stat_activity WHERE state = 'idle') as idle_connections,
  (SELECT setting::bigint FROM pg_settings WHERE name = 'max_connections') as max_allowed,
  (SELECT setting::bigint FROM pg_settings WHERE name = 'superuser_reserved_connections') as reserved_slots,
  (SELECT setting::bigint FROM pg_settings WHERE name = 'max_connections') - 
  (SELECT count(*) FROM pg_stat_activity) - 
  (SELECT setting::bigint FROM pg_settings WHERE name = 'superuser_reserved_connections') as available_slots,
  ROUND(100.0 * (SELECT count(*) FROM pg_stat_activity)::numeric / 
    (SELECT setting::bigint FROM pg_settings WHERE name = 'max_connections'), 2) as usage_percent;
$$ LANGUAGE SQL;

-- Check connection health
SELECT * FROM check_connection_health();

Integrate this query into monitoring systems (Prometheus, Grafana, DataDog) to alert when usage approaches critical thresholds (e.g., > 80%).

Advanced notes

PostgreSQL allocates shared memory for each possible connection at server startup based on the max_connections setting. This is why max_connections has context = postmaster in pg_settings and can only be changed with a full server restart — a reload via pg_reload_conf() will not apply a new value. On AWS RDS, the rds.rds_superuser_reserved_connections setting (default 2) additionally reserves slots, so actual user-available connections are further reduced. The pg_stat_activity view is essential for diagnosing connection issues—examine the query column to identify what connections are doing and which ones are stuck. For mission-critical systems, treat connection pooling as mandatory: even with high max_connections, performance degrades as connections approach the limit due to memory and scheduling overhead. PgBouncer operates in three modes: session pooling (one connection per client), transaction pooling (connection per transaction), and statement pooling (connection per statement). Transaction pooling is recommended for most web applications as it balances performance with compatibility (note that it disables session-level features like prepared statements unless configured for them). Postgres 16+ added a separate reserved_connections parameter, distinct from superuser_reserved_connections, allowing slots to be reserved for roles with the pg_use_reserved_connections privilege. For replication setups, walsenders consume connection slots governed by max_wal_senders (separate from max_connections in modern versions); verify replication connections are accounted for when sizing. Use the pg_settings view to audit current settings, including which require a restart: SELECT name, setting, context, pending_restart FROM pg_settings WHERE name LIKE '%connection%';

Frequently asked questions

What does "FATAL: remaining connection slots are reserved for non-replication sup" mean?
This PostgreSQL error occurs when the server has exhausted all available connection slots allocated for regular (non-superuser) clients. PostgreSQL reserves a portion of its maximum connections exclusively for superusers and replication roles via the superuser_reserved_connections parameter (default 3 slots). When all non-reserved slots are in use, new client connections are rejected with this FATAL error.
How do I fix "FATAL: remaining connection slots are reserved for non-replication sup"?
PostgreSQL rejects new client connections because all non-reserved slots are in use and the rest are held for superusers. Fix by freeing idle connections, adding pooling, and raising max_connections.
What causes "FATAL: remaining connection slots are reserved for non-replication sup"?
max_connections parameter set too low for application load (default 100 connections) Application connection leaks: connections opened but never properly closed Connection pooling not configured or pool size too large relative to max_connections
Is the "FATAL: remaining connection slots are reserved for non-replication sup" error serious?
Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.

Official resources & further reading