
How to Fix PostgreSQL `too many clients already` Errors
A short fix guide for connection-limit errors, idle sessions, and when to add PgBouncer instead of raising max_connections.
When PostgreSQL says too many clients already, it is refusing new connections because the server has reached its configured connection limit. That usually means one of three things: the application is opening too many connections, a worker pool grew faster than expected, or idle sessions were left hanging around long enough to crowd out new work. The fix is usually not to touch the database first. It is to find the connection source, reduce pressure at the app layer, and only then decide whether a higher limit is justified.
The fastest way to think about this error is to separate symptoms from capacity. max_connections is a hard ceiling on concurrent connections, and PostgreSQL sizes some resources directly from it. That means increasing it is not free. A managed platform can make the limit easier to understand, but it still pays to treat connection count as a design choice, not a default you only notice during an outage.
What the error usually means
The message is rarely about a single bad query. It usually means the database has more active or idle client sessions than it can safely accept. In practice, the problem comes from a bursty release, a misconfigured app pool, too many workers, or a leak that keeps connections open after work is done.
PostgreSQL also keeps a small number of slots reserved for superusers and roles with reserved-connection privileges. That is deliberate. It lets administrators still get in during saturation instead of locking out the very people who need to fix the issue.
How to spot the source quickly
Use the database itself to answer two questions: how many connections are open, and which service owns them. The exact query can vary, but the pattern is the same.
show max_connections;
select count(*) from pg_stat_activity;
select usename, application_name, state, count(*)
from pg_stat_activity
group by 1, 2, 3
order by 4 desc;
That last query usually tells the story. If one service owns most of the sessions, its pool is probably too large. If you see many rows in idle or idle in transaction, the application is holding connections longer than it should. If the spike appears only during deploys or traffic bursts, the pool size may be harmless in isolation but too large once several services are running together.
| Symptom | Likely cause | First check |
|---|---|---|
| Error appears during deploys | New replicas or workers multiplied pools | Count connections by application_name |
| Error comes and goes during spikes | Bursty traffic or serverless fan-out | Look for many short-lived sessions |
| Many sessions sit idle | The app leaves connections open | Search for idle and idle in transaction |
| Admin can still connect | Reserved slots are doing their job | Use the admin role, not the app role |
The fastest fix sequence
Start with the least risky change. If a deployment just rolled out, scale the app back, restart the leaking worker, or reduce the per-process database pool before you touch the database settings. If a background job is the source, stop that job until you know why it is holding connections.
If the app is healthy but the traffic pattern is not, put PgBouncer in front of PostgreSQL. PgBouncer is built for exactly this kind of pressure. In transaction pooling mode, a server connection is released back to the pool after each transaction, which lets many clients share fewer database connections. That is usually the right fit for web requests and short-lived work.
ArmorDB includes PgBouncer by default, and the connection guide shows how to use it cleanly: /docs/connect and /docs/pgbouncer. If your app has separate web, worker, and admin paths, pool them differently instead of giving every process the same large limit.
Only raise max_connections when you understand the tradeoff. PostgreSQL says this setting can only be changed at server start, and increasing it raises memory usage for the server. If the database is already near its practical limit, a larger number can hide the symptom while making recovery harder.
When raising the limit is actually the right move
There are cases where a higher limit is justified. A shared database that serves many small internal apps, a legacy workload that cannot be pooled immediately, or a temporary migration window may need more headroom. Even then, the right move is usually to raise the limit carefully after checking memory, not to turn it into the new default forever.
| Option | Good when | Tradeoff |
|---|---|---|
| Reduce app pool sizes | A few services are over-connecting | Requires deploy changes and coordination |
| Add PgBouncer | Requests are short and bursty | Session-heavy features need review |
Raise max_connections | You have clear headroom and a real need | More shared memory and a bigger blast radius |
A practical rule of thumb
If you are seeing this error once and the app has a clear bug, fix the bug. If you are seeing it whenever traffic rises, fix the connection model. If you are seeing it because the project has grown past the old defaults, add pooling first and sizing second. That order keeps the system simpler and avoids paying for a larger database just to make a connection leak less visible.
The main mistake to avoid is using max_connections as the first response to every spike. A bigger ceiling can buy time, but it does not solve pool misconfiguration, leaked sessions, or poor worker math. The stable pattern is conservative app pools, short transactions, and a pooler between unpredictable clients and PostgreSQL.
Sources / further reading
- PostgreSQL documentation on connection settings, including
max_connections,reserved_connections, andsuperuser_reserved_connections - PostgreSQL documentation on
pg_stat_activityand the cumulative statistics views - PgBouncer documentation on
pool_modeand server connection reuse - ArmorDB docs for connection setup and PgBouncer
Takeaway
too many clients already is a capacity signal, not just an error string. Find which service owns the connections, shrink the largest pools, add PgBouncer when the workload is bursty, and only raise max_connections when you know why the extra headroom is needed.
Topic
Quick Fixes
Updated
May 19, 2026
Read time
8 min read
ArmorDB Engineering writes about PostgreSQL operations, security, and infrastructure decisions for teams building production apps on ArmorDB.
Read next
Tech-News · 7 min read
PostgreSQL 19 Beta 1: What Managed PostgreSQL Teams Should Test Now
PostgreSQL 19 Beta 1 previews changes in maintenance, replication, security, and observability that managed PostgreSQL teams should evaluate before the final release.
Read articleData-Specs · 8 min read
PostgreSQL JSONB vs Relational Tables: How to Choose the Right Schema
A practical comparison of PostgreSQL JSONB, relational columns, and hybrid schemas for SaaS teams deciding what to model, index, and constrain.
Read article