PostgreSQLIV · Connections, Sessions and PoolingConnections
max_connections, and what it actually reserves
What you'll learn
- Compute how many slots an ordinary application role actually gets
- Explain the difference between superuser_reserved_connections and reserved_connections
- Grant an operator role emergency access without granting superuser
- Choose a connection ceiling from measured concurrency rather than from pool arithmetic
Prerequisites
Verified against PostgreSQL 18.x · PostgreSQL (comparison targets) 17.11, 16.15 · PostgreSQL (support calendar) 18, 17, 16, 15, 14 supported · pgBackRest 2.59.1 · PgBouncer 1.25.2 · Patroni 4.1.5 · Ubuntu (host baseline) 26.04 LTS · 2026-08-27
max_connections is a ceiling on the total, not an allowance for your
application. Two reservations are taken out of it before an ordinary
role gets a slot, and knowing the arithmetic is what makes the
difference between “we have 200 connections available” and the number
the application will actually be given.
The arithmetic
slots for ordinary roles
= max_connections
- superuser_reserved_connections
- reserved_connections
Demonstrated on a live cluster deliberately configured small:
$ psql -U postgres -c "SELECT name, setting FROM pg_settings WHERE name IN ('max_connections','superuser_reserved_connections','reserved_connections') ORDER BY name" name | setting
--------------------------------+---------
max_connections | 12
reserved_connections | 1
superuser_reserved_connections | 2
(3 rows)Twelve minus two minus one is nine. Twelve connections were then opened as an ordinary role:
$ psql -U postgres -tAc "SELECT count(*) FROM pg_stat_activity WHERE usename = 'app'"9$ psql -h 127.0.0.1 -U app -d postgres -c 'SELECT 1'psql: error: connection to server at "127.0.0.1", port 5432 failed:
FATAL: remaining connection slots are reserved for roles with privileges
of the "pg_use_reserved_connections" role$ psql -U postgres -tAc "SELECT 'superuser connected: ' || current_user"superuser connected: postgresThe two reservations, and why there are two
superuser_reserved_connections (default 3) has existed for a long
time. It keeps slots for superusers so that an application cannot lock
the administrator out of a cluster it has saturated.
reserved_connections (default 0) was added in PostgreSQL 16
and closes a real gap. Before it, the only way to guarantee an operator
could connect during an incident was to give them superuser — which is
a large privilege grant for a small operational need, and Part V
covers why superuser is worth avoiding.
Now you can grant the ability to use reserved slots on its own:
-- A monitoring or on-call role that must be able to connect during an
-- incident, without granting superuser
CREATE ROLE oncall LOGIN PASSWORD 'set-a-real-secret-here';
GRANT pg_monitor TO oncall;
GRANT pg_use_reserved_connections TO oncall;
Then set reserved_connections to a small number — two or three is
usually enough — and those slots are unavailable to ordinary
application roles.
Choosing the ceiling
The wrong method is to sum the application’s configured pool sizes and add headroom. That produces a number describing what the application is configured to open, which is usually far above what it concurrently uses, and every one of those slots costs memory and a share of the contention discussed in the previous lesson.
The better method starts from measurement:
# Peak concurrency actually observed, by state
psql -U postgres -c \
"SELECT state, count(*)
FROM pg_stat_activity WHERE backend_type = 'client backend'
GROUP BY state ORDER BY count(*) DESC"
# Sample it over time rather than once
psql -U postgres -c \
"SELECT now(), count(*) FILTER (WHERE state = 'active') AS active,
count(*) AS total
FROM pg_stat_activity WHERE backend_type = 'client backend'"
Sample that every ten seconds for a week and take the peak. The ceiling should sit comfortably above the peak total, and the peak active figure is the one that tells you whether you are near the concurrency plateau.
If peak total is far above peak active — which is the usual finding — the honest conclusion is that a pooler will let you lower the ceiling rather than raise it.
Production discipline
- Compute the ordinary-role allowance rather than quoting the
ceiling. It is
max_connectionsminus both reservations. - Set
reserved_connectionsand grantpg_use_reserved_connectionsto your on-call role. It defaults to 0 and it is the control that gets you in during a saturation incident without granting superuser. - Size the ceiling from measured peak concurrency, sampled over a week, not from the sum of the application pools.
- Read the refusal message carefully. “Too many clients” and “reserved for roles with privileges of” are different states with different remaining options.
- Plan
max_locks_per_transactionalongside any change tomax_connections. They size the same shared structure and both need a restart.
Cross-course references
- Secrets, PKI & Certificate Management — Part XII (Secret
management platforms) covers least-privilege role design, which is
the argument for
pg_use_reserved_connectionsover superuser. - Observability for Production Sysadmins — Part XX (Alert quality) covers alerting on connection headroom before exhaustion rather than on the exhaustion itself.
- Linux for Production Sysadmins — Part XXXVII (Resources) covers the file-descriptor and process limits that a high ceiling also consumes on the host.
Quiz
Knowledge check · 6 questions
Q1. A cluster has max_connections 200, superuser_reserved_connections 3 and reserved_connections 0. How many connections can an ordinary application role open?
Q2. What problem does reserved_connections, added in PostgreSQL 16, solve that superuser_reserved_connections did not?
Q3. Which are sound inputs to choosing max_connections? Select all that apply.
Q4. PostgreSQL checks the connection limit before authenticating the client, so a rejected connection costs the server almost nothing.
Q5. Name the two distinct connection-refusal messages PostgreSQL produces and explain why the difference matters during an incident.
Q6. Give the immediate action and the change that prevents a recurrence.
At 01:50 an application deployment introduces a connection leak. By 02:05 the cluster is refusing connections and the application is failing. The on-call engineer attempts to connect with their normal operator account and is refused. They spend eleven minutes locating superuser credentials in a password vault before they can connect and investigate. The cluster runs PostgreSQL 18 with max_connections 300, superuser_reserved_connections 3, and reserved_connections at its default.
Passing score: 75%. Answers are checked in this browser.