Errore PostgreSQL: sorry, too many clients already
FATAL: sorry, too many clients already
Ogni slot di connessione sul server è occupato, quindi PostgreSQL rifiuta quello nuovo. Il server è per il resto in salute — è semplicemente pieno. Una variante ravvicinata dello stesso problema è il messaggio su "remaining connection slots are reserved": gli ultimi slot sono tenuti da parte per i superuser, così un amministratore può comunque entrare e sistemare le cose.
Cosa significa questo errore
PostgreSQL accetta al massimo max_connections connessioni concorrenti (default: 100) e ne riserva alcune (superuser_reserved_connections, default: 3) per i superuser. Quando un client normale chiede una connessione oltre il limite non riservato, riceve questo FATAL al momento della connessione — la connessione è rifiutata, nient'altro sul server ne risente.
Ogni connessione è un processo server dedicato con la propria memoria, quindi il limite esiste per una ragione: PostgreSQL non gestisce con eleganza migliaia di connessioni dirette. Ecco perché la soluzione duratura non è quasi mai "alza il numero".
Cause comuni
- Nessun connection pooler davanti al database, con molte istanze applicative che aprono ciascuna il proprio pool. Dieci servizi × 20 connessioni ciascuno = 200 prima di qualsiasi picco di traffico.
- Connection leak: percorsi di codice che aprono connessioni e non le restituiscono mai al pool.
- Sessioni bloccate in
idle in transactionche tengono slot (e lock, e progresso del vacuum) indefinitamente. - Worker serverless / con autoscaling, ciascuno che apre nuove connessioni per invocazione.
- Un rallentamento altrove: se le query improvvisamente impiegano 10× di più, le connessioni si accumulano man mano che i chiamanti vanno in timeout e riprovano. L'errore è il sintomo; la query lenta è la malattia.
Come diagnosticarlo
Connettiti come superuser (è a questo che servono gli slot riservati) e guarda chi tiene gli slot:
SHOW max_connections;
SELECT state, count(*)
FROM pg_stat_activity
GROUP BY state ORDER BY count(*) DESC;
SELECT usename, application_name, count(*)
FROM pg_stat_activity
GROUP BY 1, 2 ORDER BY count(*) DESC;
-- Sessioni in transazione da più tempo (candidati leak):
SELECT pid, usename, state, now() - xact_start AS xact_age, left(query, 60)
FROM pg_stat_activity
WHERE xact_start IS NOT NULL
ORDER BY xact_start
LIMIT 10;
Molte connessioni idle indicano pool applicativi sovradimensionati o con leak; vecchie sessioni idle in transaction indicano codice applicativo che ha aperto una transazione e se n'è andato.
Come risolverlo
- Metti un pooler davanti (PgBouncer in transaction mode è la risposta standard): migliaia di connessioni client vengono multiplexate su poche decine di connessioni server. È la soluzione che scala; controlla prima che il tuo carico non dipenda da stato di sessione (
SETa livello di sessione, advisory lock, prepared statement tra transazioni) che il transaction pooling non preserva. - Sistema i leak: limita ogni pool (dimensione massima, durata massima, idle timeout) e assicurati che le connessioni siano restituite in una pulizia stile
finally. - Limita i danni lato server:
ALTER ROLE app_user CONNECTION LIMIT 50; ALTER SYSTEM SET idle_in_transaction_session_timeout = '5min'; SELECT pg_reload_conf(); - Alza
max_connectionssolo con cognizione (richiede un riavvio): ogni slot è un processo con un costo di memoria reale, e centinaia di backend attivi di solito hanno prestazioni peggiori di poche decine con pooling.
idle in transaction non mangiano solo slot: trattengono il vacuum per l'intero database.
