Sorry, too many clients already
Every connection slot on the Postgres server is taken, usually by serverless functions that each open connections of their own.
Also appears as
- remaining connection slots are reserved for roles with the SUPERUSER attribute
- remaining connection slots are reserved for non-replication superuser connections
Prompt to fix it
Our database refuses connections with "sorry, too many clients already" (or "remaining connection slots are reserved"). Find every place the app creates a database client or pool. Make it create one shared client per server instance instead of one per request, reuse it across hot reloads in development, and connect serverless code through the Supabase transaction pooler (port 6543) with prepared statements turned off for our driver. Keep pool sizes small. Don’t just raise max_connections; find and fix what opens the extra connections.
Paste into Layerwise or any AI coding tool.
What it means
Postgres allows a fixed number of open connections, set by max_connections, and holds a few back for admins. When the regular slots run out, new connections are refused with one of these messages. Smaller Supabase compute sizes allow fewer connections, so small projects hit this early.
Serverless hosting makes it easy to run out. On Vercel or Netlify, every function instance opens its own connections, and a traffic spike multiplies them. In development, hot reload can create a new database client on every file save without closing the old one.
The fix is a connection pooler: a service that keeps a few real connections open and shares them among many short requests. Supabase includes one, and its transaction mode on port 6543 is the one meant for serverless functions. Calls made through supabase-js go over HTTP to Supabase’s API, which has its own pool, so they open no database connections from your app.
Common causes
- Serverless functions use the direct connection string on port
5432, so every instance opens its own connections. - The code creates a new client or pool inside the request handler and never closes it.
- Hot reload in development creates a fresh Prisma or
pgclient on every save. - Each instance’s pool is large, like the
pgdefault of 10, and many instances run at once. - A query or transaction never releases its connection, so open connections pile up.
How to fix it
- In Supabase, click Connect and copy the transaction pooler string (port
6543). Use it as the database URL for serverless code. - Turn off prepared statements, which transaction mode doesn’t support: add
?pgbouncer=trueto the URL for Prisma, or passprepare: falseto postgres.js. - Create the database client once at module level and reuse it. In development, keep it on
globalThisso hot reload doesn’t make another. - Keep each serverless pool small, around one connection per instance.
- Run
select usename, application_name, count(*) from pg_stat_activity group by 1, 2 order by 3 desc;to see what holds the connections.
Example fix
import postgres from 'postgres';
// One client per server instance, reused across hot reloads in development.
const globalForDb = globalThis as unknown as { sql?: postgres.Sql };
export const sql =
globalForDb.sql ??
// DATABASE_URL is Supabase's transaction pooler string (port 6543).
postgres(process.env.DATABASE_URL!, {
prepare: false, // transaction mode doesn't support prepared statements
max: 1
});
if (process.env.NODE_ENV !== 'production') globalForDb.sql = sql;Related errors
All errorsFUNCTION_INVOCATION_TIMEOUT
A Vercel Function ran past its time limit, so Vercel stopped it and returned a 504 in place of your response.
500 Internal Server Error
The server’s code threw an error or crashed while handling the request, and the real error message is waiting in the server logs.
net::ERR_CONNECTION_REFUSED
Nothing was listening at that address and port, usually because the server isn’t running or the app is calling the wrong port.
New row violates row-level security policy
Postgres refused to save a row because no row-level security policy on that table lets the current user write it.
Build with an agent that checks its work
The Layerwise agent clicks through the live preview and reads the console, so it catches errors before you do.