Fix PostgreSQL FATAL sorry, too many clients already

Beginner 20 min Oct 11, 2026
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Learn why PostgreSQL throws FATAL: sorry, too many clients already, how to check and close idle connections, safely raise max_connections, and prevent the error from coming back with connection pooling.

Prerequisites

  • Running PostgreSQL 13 or later instance
  • Sudo or root access to the database server
  • Basic familiarity with psql

What this solves

PostgreSQL rejects new connections with FATAL: sorry, too many clients already when the number of active sessions hits max_connections. This guide shows you how to diagnose the cause, clear stuck connections, raise the limit safely, and stop it from recurring with pooling and monitoring.

Step-by-step configuration

Understand why the limit exists

PostgreSQL reserves a fixed amount of shared memory and worker processes for each connection slot defined by max_connections. Every client connection, including ones from application servers, cron jobs, and admin tools, consumes one slot for as long as it stays open, even if it is idle.

A few slots are always reserved for the superuser via superuser_reserved_connections, so that an administrator can still log in to diagnose problems even when the pool is full. When all remaining slots are taken, every new connection attempt fails immediately with this FATAL error.

Note: This is not a crash. PostgreSQL is working as designed to protect itself from running out of memory or file descriptors. The fix is almost always in how connections are opened and closed, not in the database engine itself.

Check the current connection count and limit

Connect to PostgreSQL with psql and inspect how many connections are currently open compared to the configured maximum.

sudo -u postgres psql -c "SHOW max_connections;"
sudo -u postgres psql -c "SELECT count(*) FROM pg_stat_activity;"

Compare the two numbers. If the count from pg_stat_activity is close to or equal to max_connections, you have confirmed the cause of the error.

sudo -u postgres psql -c "SELECT datname, usename, client_addr, state, count(*) FROM pg_stat_activity GROUP BY datname, usename, client_addr, state ORDER BY count(*) DESC;"

Identify idle or leaked connections

Most connection exhaustion comes from applications that open a connection per request and never close it, or from connection pools that are misconfigured with a pool size larger than the database can handle. Look specifically at the idle and idle in transaction states.

sudo -u postgres psql -c "SELECT pid, usename, datname, state, now() - state_change AS idle_for, query FROM pg_stat_activity WHERE state LIKE 'idle%' ORDER BY idle_for DESC LIMIT 20;"

Connections stuck in idle in transaction for a long time usually indicate an application bug where a transaction was opened but never committed or rolled back. These hold locks and slots indefinitely.

Warning: Do not kill connections blindly in production. Review the query and client_addr columns first to confirm you are not terminating a long-running legitimate job such as a backup or migration.

Terminate stuck sessions safely

Once you have identified connections that are genuinely idle or stuck, terminate them individually by PID rather than cancelling everything at once.

sudo -u postgres psql -c "SELECT pg_terminate_backend(12345);"

To free up slots quickly during an incident, terminate all connections idle in transaction for more than 10 minutes, but review the list first.

sudo -u postgres psql -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'idle in transaction' AND now() - state_change > interval '10 minutes';"

This buys you immediate headroom while you fix the root cause in the application or pooler configuration.

Increase max_connections

If legitimate traffic genuinely needs more concurrent connections than the current limit allows, raise max_connections in the PostgreSQL configuration file. Each additional connection consumes roughly a few megabytes of shared memory, so increase gradually and monitor memory usage.

sudo -u postgres psql -c "SHOW config_file;"

Edit the file returned by the command above, typically located under /etc/postgresql/17/main/postgresql.conf on Debian based systems or /var/lib/pgsql/17/data/postgresql.conf on RHEL based systems.

max_connections = 200
shared_buffers = 2GB
superuser_reserved_connections = 5

A common rule of thumb is to keep shared_buffers around 25% of total RAM and scale it up slightly as max_connections increases, since each connection needs its own memory for sorting and work operations.

Raise kernel limits to match

Higher max_connections values require more file descriptors and more shared memory at the OS level. Check and raise the open file limit for the postgres user.

sudo -u postgres bash -c 'ulimit -n'
postgres soft nofile 65536
postgres hard nofile 65536
postgres soft nproc 4096
postgres hard nproc 4096

If PostgreSQL runs under systemd, also raise the limit in the service unit override so it takes effect even if limits.conf is ignored.

sudo systemctl edit postgresql
[Service]
LimitNOFILE=65536

Check shared memory settings on the OS

On some installations, especially AlmaLinux and Rocky Linux with default kernel settings, the shared memory limits are too low for a large max_connections plus shared_buffers combination. Check the current kernel shared memory maximum.

sysctl kernel.shmmax kernel.shmall
sysctl kernel.shmmax kernel.shmall

If shmmax is lower than the memory PostgreSQL needs to allocate, increase it via sysctl.

kernel.shmmax = 17179869184
kernel.shmall = 4194304
sudo sysctl --system

Restart PostgreSQL safely

max_connections and shared_buffers both require a full restart, not just a reload, because they affect shared memory allocation at startup. Schedule this during a maintenance window and verify there are no critical queries running first.

sudo -u postgres psql -c "SELECT pid, state, query FROM pg_stat_activity WHERE state != 'idle';"
sudo systemctl restart postgresql

Check the PostgreSQL logs immediately after restart to confirm it came back up cleanly with the new settings.

sudo journalctl -u postgresql -n 50 --no-pager

Verify your setup

sudo -u postgres psql -c "SHOW max_connections;"
sudo -u postgres psql -c "SELECT count(*) AS active, (SELECT setting::int FROM pg_settings WHERE name='max_connections') AS max FROM pg_stat_activity;"

Confirm the new max_connections value is active and that current usage sits comfortably below it. Also confirm PostgreSQL is accepting new connections from your application.

psql -h 203.0.113.10 -U appuser -d appdb -c "SELECT 1;"

Prevent recurrence with connection pooling

Raising max_connections only buys time. The real fix for most applications is to route connections through a pooler so the database only ever sees a small, stable number of backend connections regardless of how many application workers or web requests exist.

PgBouncer sits between your application and PostgreSQL, reusing a small pool of real database connections across many client connections. This is the standard production pattern and avoids the memory overhead of scaling max_connections into the thousands.

See Install and configure PgBouncer for PostgreSQL connection pooling for a full setup guide, or Configure PostgreSQL 17 connection pooling with PgBouncer for high availability if you are running a replicated setup.

Note: If your application uses an ORM or framework-level connection pool such as SQLAlchemy or Django, make sure its pool size multiplied by the number of application workers does not exceed max_connections minus the connections your pooler and admin tools need.

Monitor connections to catch this before it happens again

Set up alerting on connection count as a percentage of max_connections so you get paged before clients start seeing FATAL errors, not after. Track it alongside query latency and lock waits.

See Monitor PostgreSQL performance with Prometheus and Grafana dashboards and Monitor PostgreSQL performance with pg_stat_statements extension for query analysis and optimization to build out proper visibility into connection usage and slow queries.

Common issues

SymptomCauseFix
FATAL: sorry, too many clients already on every new connectionmax_connections slots fully consumedTerminate idle sessions, then raise max_connections and restart PostgreSQL
Error persists even after terminating idle sessionsApplication keeps opening new connections faster than old ones closeAdd connection pooling with PgBouncer in transaction mode
PostgreSQL fails to start after raising max_connectionsKernel shared memory limit too low for the new shared_buffers and max_connections combinationRaise kernel.shmmax and kernel.shmall via sysctl, then restart
Many connections stuck in idle in transactionApplication opens a transaction but never commits or rolls backFix transaction handling in application code, set idle_in_transaction_session_timeout
Superuser also locked outsuperuser_reserved_connections exhausted alongside regular slotsIncrease superuser_reserved_connections slightly and always keep an emergency admin path

Next steps

Running this in production?

Want this handled for you? This works for a single server. When you run multiple environments or need PostgreSQL available 24/7 under real traffic, catching connection exhaustion before it pages your users is a different job. See how we run infrastructure like this for European teams.
#postgresql #database #troubleshooting #connection-pooling #pgbouncer

Don't want to manage this yourself?

We handle infrastructure for businesses that depend on uptime. Fully managed, with one fixed contact who knows your setup.

You get one fixed contact who knows your setup

Rotterdam 12:45 · reachable in a message, no ticket form