Error de PostgreSQL: sorry, too many clients already
FATAL: sorry, too many clients already
Cada slot de conexión del servidor está ocupado, así que PostgreSQL rechaza el nuevo. Por lo demás el servidor está sano — simplemente está lleno. Una variante cercana del mismo problema es el mensaje sobre "remaining connection slots are reserved": los últimos slots se reservan para superusuarios para que un administrador aún pueda entrar y arreglar las cosas.
Qué significa este error
PostgreSQL acepta como máximo max_connections conexiones concurrentes (por defecto: 100), y reserva unas cuantas de ellas (superuser_reserved_connections, por defecto: 3) para superusuarios. Cuando un cliente normal pide una conexión más allá del límite no reservado, obtiene este FATAL en el momento de conectar — la conexión se rechaza, nada más en el servidor se ve afectado.
Cada conexión es un proceso de servidor dedicado con su propia memoria, así que el límite existe por una razón: PostgreSQL no maneja miles de conexiones directas de forma elegante. Por eso la solución duradera casi nunca es "sube el número".
Causas comunes
- No hay pooler de conexiones delante de la base de datos, con muchas instancias de aplicación abriendo cada una su propio pool. Diez servicios × 20 conexiones cada uno = 200 antes de cualquier pico de tráfico.
- Fugas de conexiones: rutas de código que abren conexiones y nunca las devuelven al pool.
- Sesiones atascadas en
idle in transactionsosteniendo slots (y bloqueos, y el progreso del vacuum) indefinidamente. - Workers serverless / con autoescalado, cada uno abriendo conexiones nuevas por invocación.
- Una ralentización en otro lugar: si de repente las consultas tardan 10× más, las conexiones se acumulan a medida que los llamantes agotan su timeout y reintentan. El error es el síntoma; la consulta lenta es la enfermedad.
Cómo diagnosticarlo
Conéctate como superusuario (para eso están los slots reservados) y mira quién sostiene los slots:
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;
-- Sesiones en transacción desde hace más tiempo (candidatas a fuga):
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;
Muchas conexiones idle apuntan a pools de aplicación sobredimensionados o con fugas; sesiones idle in transaction antiguas apuntan a código de aplicación que abrió una transacción y se despistó.
Cómo solucionarlo
- Pon un pooler delante (PgBouncer en modo transacción es la respuesta estándar): miles de conexiones de cliente se multiplexan sobre unas pocas docenas de conexiones de servidor. Esta es la solución que escala; comprueba primero que tu carga de trabajo no dependa de estado de sesión (
SETa nivel de sesión, advisory locks, prepared statements a través de transacciones) que el pooling por transacción no preserva. - Arregla las fugas: acota cada pool (tamaño máximo, vida máxima, idle timeout) y asegúrate de que las conexiones se devuelvan en una limpieza estilo
finally. - Limita el daño en el servidor:
ALTER ROLE app_user CONNECTION LIMIT 50; ALTER SYSTEM SET idle_in_transaction_session_timeout = '5min'; SELECT pg_reload_conf(); - Sube
max_connectionssolo de forma deliberada (requiere un reinicio): cada slot es un proceso con un coste de memoria real, y cientos de backends activos normalmente rinden peor que unas pocas docenas con pooling.
idle in transaction no solo consumen slots: retienen el vacuum de toda la base de datos.
