Too many connections / remaining connection slots are reserved
Fix "sorry, too many clients already" and "remaining connection slots are reserved" on SupaHost, where 400 connections are shared by every project on the instance.
What you see
When a client tries to open a new connection:
FATAL: 53300: sorry, too many clients already
or
FATAL: 53300: remaining connection slots are reserved for roles with the SUPERUSER attribute
On SupaHost you'd normally see these from your own tools connected through the SSH tunnel (psql, an ORM, a migration runner). Through the Data API, a shortage of connections shows up as slow requests or PGRST003 errors instead.
Why it happens
Postgres has a fixed number of connection slots (max_connections), and a few are held back for administrators. When the rest are in use, new connections are refused. Each connection is a separate server process using memory, so the limit protects the VM.
On SupaHost, one Postgres server serves every project on the instance, with max_connections = 400 shared between them. Each project's services use small fixed pools (5 connections for the Data API and 5 for Auth), plus a few for Storage, Realtime and Studio while it's open. Those rarely add up to 400. The usual culprit is client-side pooling:
- An ORM pool of 10 to 20 connections in each app process, multiplied by several processes or workers.
- Dev servers with hot reload that create a new pool on every reload without closing the old one.
- Scripts that open a connection per task and never close it.
- Sessions left
idle in transactionby a crashed script or an open psql prompt.
How to fix it
See who holds the connections, across all projects:
select datname, usename, application_name, state, count(*) from pg_stat_activity group by datname, usename, application_name, state order by count(*) desc;datnameis the project database (p_<project>). Many rows forpostgreswith stateidleusually means a client pool.Close idle connections that your own tools left open. The
postgresrole can end sessions of its own role:select pg_terminate_backend(pid) from pg_stat_activity where usename = 'postgres' and datname = current_database() and state in ('idle', 'idle in transaction') and state_change < now() - interval '10 minutes' and pid <> pg_backend_pid();Studio also connects as
postgres; if you close its connections, it reconnects on the next query.Cap your client pools. Five connections per process is plenty for most apps:
import pg from 'pg' const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL, max: 5, idleTimeoutMillis: 30_000, })For Prisma, add
connection_limit=5to the connection string.Create one pool per process and reuse it. In dev servers, keep the pool on a global so hot reloads don't create new ones.
Have abandoned transactions closed automatically, for example in the connection string:
?options=-c%20idle_in_transaction_session_timeout%3D60000(60 seconds).
On SupaHost
- There's no connection pooler (Supavisor or PgBouncer) on SupaHost, so every client connection is a real Postgres connection. The Data API pools for you, which is why browser and mobile apps should use supabase-js rather than connect to Postgres.
- Direct connections are only possible on Business and Enterprise, through the SSH tunnel. Serverless functions that open a fresh connection per request are a poor fit; use the Data API or an Edge Function instead.
max_connectionsis the same on every plan, so upgrading doesn't add slots. It does add memory, which helps if you're running many connections at once.