Postgres "Too Many Clients Already": How to Fix It

"Too many clients already" means Postgres hit max_connections. Find who holds connections in pg_stat_activity, shrink app pools, and only then raise the limit.
The error usually arrives all at once: the API starts failing every request with FATAL: sorry, too many clients already, or remaining connection slots are reserved for roles with the SUPERUSER attribute on Postgres 16 and later. Restarting the app makes it go away for a while, then it's back. It's almost never "too many users". It's too many connection pools, each holding more connections than you think. My own API runs NestJS with Prisma 7 and Postgres, so the Node examples below are the ones I actually use.
Key takeaways
- Count connections, don't guess:
pg_stat_activityshows who holds each one and whether it's active, idle or stuck "idle in transaction". - Do the math: total connections = app processes × pool size + workers + cron jobs + your admin tools. PM2 cluster mode and replicas multiply it.
- Prisma 7 with driver adapters defaults to 10 connections per client; Prisma 6 defaulted to CPU cores × 2 + 1. Set it explicitly.
- Kill stuck sessions with timeouts (
idle_in_transaction_session_timeout) instead of by hand every night. - Raise
max_connectionslast. Each connection costs memory. A pooler like PgBouncer scales better.
Step 1: Get in and see who holds the connections
Postgres keeps a few slots (superuser_reserved_connections, 3 by default) for superusers exactly for this moment. Connect as one:
sudo -u postgres psql # in Docker: docker exec -it db psql -U postgres
SHOW max_connections; SELECT count(*) FROM pg_stat_activity; SELECT usename, application_name, client_addr, state, count(*) FROM pg_stat_activity WHERE backend_type = 'client backend' GROUP BY 1, 2, 3, 4 ORDER BY 5 DESC;
This tells you which user, app and host hold the slots and in what state:
- Mostly
idlefrom one app: pools that are too big, or too many processes each with their own pool. idle in transaction: code that opened a transaction and never committed or rolled back. These hold locks too and are the most dangerous.- Many
active: slow queries piling up. More connections won't help; faster queries will.
Step 2: Free slots right now
To get the site back while you fix the cause, end sessions stuck in a transaction for more than a few minutes:
SELECT pg_terminate_backend(pid), now() - state_change AS stuck_for, left(query, 60) FROM pg_stat_activity WHERE state = 'idle in transaction' AND now() - state_change > interval '5 minutes';
Restarting the app also releases its connections. Both are first aid; the next steps stop it coming back.
Step 3: Do the connection math
Write it down for every client of the database:
API: 4 PM2 cluster instances × pool 10 = 40
Workers: 2 queue workers × pool 10 = 20
Next.js: 2 instances × pool 10 = 20
Cron jobs, migrations, admin tools ~ 10
total ~ 90 (of 97 usable)
This is how a small site hits 100 without much traffic. The usual multipliers:
- PM2 cluster mode, Docker replicas and Kubernetes pods: every process has its own pool.
- Serverless functions: each concurrent function instance can open its own connections. Use a pooler or your provider's pooled connection string.
- Creating a new client per request instead of one shared client per process. Each new client opens a new pool.
- Hot reload in development: every reload creates another client unless you keep one on
globalThis.
Step 4: Set pool sizes explicitly
Prisma 7 (driver adapters)
In Prisma 7 the pool belongs to the driver. With @prisma/adapter-pg it's a pg pool, default 10 connections per client:
import { PrismaClient } from "@prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL,
max: 5, // per process; multiply by your instance count
});
export const prisma = new PrismaClient({ adapter });
Prisma 6 and earlier
The pool was built into the query engine and sized from CPU cores. Set it in the URL: postgresql://…/app?connection_limit=5. Upgrading from 6 to 7 changes the default, so check this after the upgrade.
node-postgres, TypeORM, Sequelize, Knex
All have a pool max option. The pg default is 10. Create one pool per process at startup and reuse it everywhere.
A good starting point: keep the total of all pools under about 80% of max_connections, leaving room for migrations, backups and you.
Step 5: Add timeouts so leaks clean themselves up
ALTER DATABASE app SET idle_in_transaction_session_timeout = '60s'; ALTER DATABASE app SET statement_timeout = '30s'; -- Postgres 14+: close sessions idle for a long time (careful with poolers) ALTER ROLE report_user SET idle_session_timeout = '10min';
New sessions pick these up. idle_in_transaction_session_timeout is the important one: it ends the session that forgot to commit, which also releases its locks.
Step 6: Raise max_connections or add PgBouncer
If the math says you really need more connections, you can raise the limit. It needs a restart, and each connection uses memory, so a small VPS can trade a connection error for the OOM killer (see the Linux OOM killer guide):
ALTER SYSTEM SET max_connections = 200; -- then: sudo systemctl restart postgresql
For many app processes or serverless, a pooler is the better answer. PgBouncer in transaction mode lets hundreds of clients share a few dozen real connections. Some features (session-level prepared statements, SET, advisory locks) behave differently through it, so check your ORM's PgBouncer notes for your version before switching.
While you're in the database config: if Postgres runs in Docker with ports: "5432:5432", it's probably reachable from the internet despite UFW. Read why Docker bypasses UFW.
Frequently asked questions
What does "sorry, too many clients already" mean in Postgres?
Every connection slot allowed by max_connections is in use, so Postgres refuses new connections. It usually means app connection pools are too large or connections are leaking, not that you have too many users.
What does "remaining connection slots are reserved" mean?
All normal slots are used and only the few reserved for superusers are left. You can still log in as the postgres superuser to investigate. Postgres 16 changed the wording to "reserved for roles with the SUPERUSER attribute".
What is Prisma's default connection pool size?
In Prisma 7 with driver adapters such as @prisma/adapter-pg, the pool comes from the driver and defaults to 10 connections. In Prisma 6, the default was the number of physical CPU cores times two plus one, set with connection_limit in the URL.
Should I just increase max_connections?
Only after you've sized the pools and fixed leaks. Each connection is a separate process that uses memory, so raising the limit a lot on a small server can cause memory problems. A pooler such as PgBouncer scales further.
How do I find idle in transaction connections?
Query pg_stat_activity for rows where state is 'idle in transaction' and look at now() minus state_change. Set idle_in_transaction_session_timeout so Postgres ends them automatically.
Database refusing connections right now?
I fix Postgres connection, performance and pooling problems in Node.js and NestJS apps, and size them so the next traffic spike doesn't take the API down. See my web development services or contact me now with the error and the output of the pg_stat_activity query above.
Written by
MD Rakibul Islam Rakib
Full-stack developer, DevOps engineer and Linux system administrator with 5+ years of production experience. I deploy, harden and fix servers and web apps for clients worldwide, and everything in this article runs on real servers I manage, including this site.
- Postgres too many clients already
- remaining connection slots are reserved
- Prisma connection pool
- max_connections
- PgBouncer
- pg_stat_activity
- Node.js


