Error "FATAL: remaining connection slots are reserved" en PostgreSQL durante picos de facturación
Por Kevin Marcondes · Publicado el · 8 min de lectura
El error "FATAL: remaining connection slots are reserved" en PostgreSQL durante un pico de facturación indica que casi todos los slots de conexión se han agotado y los restantes están reservados para el superusuario. El efecto habitual es que la aplicación no puede iniciar sesión. Aquí verás cómo diagnosticar en minutos, liberar conexiones de forma segura y aplicar correcciones rápidas para estabilizar el entorno.
Qué significa este error y por qué aparece
PostgreSQL reserva algunos slots de conexión para el superusuario. Cuando los demás se agotan, los usuarios normales reciben ese error. Suele ocurrir en picos, tormentas de conexiones o cuando hay sesiones atascadas en "idle in transaction".
No siempre es solo un tema de max_connections. La ausencia de pooler, reinicios simultáneos de workers web y jobs paralelos agravan la situación. Si el problema es una saturación genérica, consulta también la guía «Too many connections». Para cargas continuas y elevadas, revisa el hardening y tuning de PostgreSQL.
- Conexiones normales agotadas; solo quedan los slots reservados para el superusuario.
- Aplicaciones sin pool aumentan los picos al abrir muchas conexiones cortas.
- Sesiones "idle in transaction" mantienen slots ocupados durante mucho tiempo.
Qué comprobar primero durante el pico
Necesitas visibilidad inmediata: cuántos slots hay, quién los ocupa y en qué estado. Prioriza acceso administrativo y, si es posible, conecta por socket local para reducir dependencia de la red.
Usa consultas rápidas para ver límites, agrupar por estado/usuario/aplicación y listar las sesiones más activas o atascadas. Esos datos guiarán las primeras acciones con menor riesgo.
-- Limites atuais
SELECT name, setting FROM pg_settings
WHERE name IN ('max_connections','superuser_reserved_connections');
-- Quem está ocupando mais conexões agora?
SELECT state, application_name, usename, client_addr, count(*) AS qtd
FROM pg_stat_activity
GROUP BY 1,2,3,4
ORDER BY qtd DESC;
-- Top sessões ativas ou presas em transação
SELECT pid, state, xact_start, wait_event_type, wait_event, application_name, query
FROM pg_stat_activity
WHERE state IN ('active','idle in transaction')
ORDER BY xact_start NULLS LAST
LIMIT 20;
Cómo liberar conexiones con seguridad sin reiniciar
Cancela consultas largas antes de terminar sesiones. Terminar una sesión fuerza un rollback de la transacción; elige objetivos de bajo riesgo y comunica al equipo de negocio.
Reduce la tasa de nuevas conexiones desde la aplicación: activa o ajusta el pool del driver, limita temporalmente procesos web y suspende tareas en segundo plano no críticas hasta que se estabilice.
- Cancelar consultas antes de finalizar sesiones reduce el impacto.
- Actúa primero sobre sesiones "idle in transaction" muy antiguas.
- Disminuye nuevas conexiones en la capa de aplicación durante la normalización.
-- 1) Cancelar consultas em execução (encerra com graça)
SELECT pg_cancel_backend(pid)
FROM pg_stat_activity
WHERE state = 'active' AND now() - xact_start > interval '30 seconds';
-- 2) Encerrar sessões problemáticas (gera rollback)
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle in transaction' AND now() - xact_start > interval '2 minutes';
Qué ajustes rápidos en PostgreSQL ayudan durante el pico
Algunos parámetros alivian la saturación, pero cambios en max_connections y superuser_reserved_connections requieren reinicio. Planifica memoria y pruebas antes de modificar.
El camino sostenible es mantener un límite razonable de conexiones en PostgreSQL y poner un pooler delante. Esto reduce churn y estabiliza la latencia bajo pico.
| Componente | Parámetro/Opción | Qué hace | Riesgo/Observación |
|---|---|---|---|
| PostgreSQL | max_connections | Aumenta el número de conexiones simultáneas aceptadas. | Requiere reinicio; más conexiones elevan el uso de memoria y el número de cambios de contexto. |
| PostgreSQL | superuser_reserved_connections | Reserva slots para que el superusuario acceda cuando la base está saturada. | Requiere reinicio; no lo dejes en 0. Mantén pocos, pero suficientes. |
| PgBouncer | pool_mode = transaction | Reutiliza conexiones por transacción, reduciendo la saturación. | Rompe recursos de sesión (tablas temporales, prepared statements por sesión, LISTEN/NOTIFY). |
| PgBouncer | reserve_pool_size | Mantiene conexiones de servidor de reserva para picos. | Ajustar junto con max_client_conn y default_pool_size. |
| SO (Linux) | net.core.somaxconn | Aumenta la cola de aceptación de conexiones (accept queue). | Ayuda durante ráfagas; no resuelve el desborde de max_connections. |
| SO (Linux) | net.ipv4.tcp_max_syn_backlog | Aumenta la cola de SYN pendientes en el handshake. | Reduce pérdidas en picos; no sustituye a un pooler. |
| Aplicación | Pool en el driver/ORM | Reutiliza conexiones y limita concurrencia. | Evita abrir/cerrar por cada petición; prefiere conexiones persistentes. |
# Exemplos no postgresql.conf (requer restart)
max_connections = 300
superuser_reserved_connections = 3
Pool de conexiones: cuándo usar PgBouncer y qué modos elegir
Utiliza PgBouncer cuando la aplicación abre muchas conexiones cortas o hay varios procesos que suben en paralelo. El modo transaction pooling cubre la mayoría de escenarios web al reducir sesiones en el servidor.
Evita transaction pooling si necesitas estado de sesión, como tablas temporales, prepared statements por sesión o LISTEN/NOTIFY. En ese caso usa session pooling o adapta la aplicación.
- Transaction pooling: ideal para HTTP con consultas cortas y alta tasa de peticiones.
- Session pooling: preserva la sesión, pero escala menos.
- Ajusta max_client_conn, default_pool_size y reserve_pool_size según la carga.
# Exemplo mínimo de PgBouncer
[databases]
mydb = host=127.0.0.1 port=5432 dbname=mydb
[pgbouncer]
listen_port = 6432
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 50
min_pool_size = 5
reserve_pool_size = 20
server_reset_query = DISCARD ALL
Backlog y kernel para aguantar tormentas de conexiones
Ráfagas de nuevas conexiones pueden encolar el accept del sistema. Ajustar somaxconn y tcp_max_syn_backlog reduce rechazos durante picos, sin crear más slots en PostgreSQL.
La corrección estructural sigue siendo limitar concurrencia con un pooler y reutilizar conexiones en la app. El backlog es complementario y debe validarse en staging. Cambios en sysctl afectan todo el sistema.
- Persistir ajustes en /etc/sysctl.d/ y versionar el archivo.
- Probar en entorno de staging antes de producción.
- Monitorear nuevas conexiones por segundo y fallos de handshake.
# Ajustes temporários (teste controlado)
sudo sysctl -w net.core.somaxconn=4096
sudo sysctl -w net.ipv4.tcp_max_syn_backlog=8192
# Persistir em /etc/sysctl.d/99-tuning.conf
# net.core.somaxconn=4096
# net.ipv4.tcp_max_syn_backlog=8192
# sudo sysctl --system
Cómo evitar que vuelva a ocurrir
Define límites claros y crea visibilidad continua. Métricas y alertas sobre conexiones, estados de sesión y tiempo de transacción evitan repeticiones durante picos de facturación.
Crea un runbook con consultas de diagnóstico y criterios para cancelar o terminar sesiones. Entrena al equipo y valida el plan. Para disciplina transaccional, consulta la guía de migraciones y rollbacks en PostgreSQL y usa alertas y runbooks como en el servicio de observabilidad y runbooks.
- Recolecta métricas: conexiones activas, nuevas conexiones por segundo y "idle in transaction".
- Alerta cuando "idle in transaction" supere un umbral definido.
- Simula picos con carga sintética para validar configuraciones.
Preguntas frecuentes
¿Aumentar max_connections resuelve el error definitivamente?
No. Aumentar max_connections alivia a corto plazo, pero puede empeorar la latencia y el consumo de memoria. La solución sostenible es usar pool de conexiones (PgBouncer o en el driver) y corregir sesiones largas, combinado con un ajuste moderado del límite.
¿Puedo cambiar superuser_reserved_connections sin reiniciar PostgreSQL?
No. superuser_reserved_connections, al igual que max_connections, requiere reinicio del servidor. Planifica una ventana y valida la memoria antes. Para alivio inmediato, cancela/termina sesiones y reduce nuevas conexiones vía pooler y la aplicación.
¿Cómo identificar rápidamente quién consume más conexiones en este momento?
Agrupa pg_stat_activity por state, application_name, usename y client_addr. Las cuentas por grupo muestran qué servicios, usuarios u hosts están saturando. Filtra por "idle in transaction" y duración de la transacción para priorizar acciones de menor riesgo.
¿Qué rompe PgBouncer en transaction pooling?
Transaction pooling no preserva el estado de sesión entre comandos. Recursos como tablas temporales, prepared statements por sesión, SET LOCAL y LISTEN/NOTIFY pueden fallar. Si los necesitas, usa session pooling o adapta la app para transacciones cortas y sin estado.
¿Es mejor matar sesiones o solo cancelar consultas largas?
Empieza con pg_cancel_backend, que intenta finalizar la consulta sin derribar la sesión. Si no funciona, usa pg_terminate_backend en sesiones de bajo riesgo, sabiendo que provocará rollback. Prioriza sesiones "idle in transaction" antiguas y queries claramente bloqueadas.
¿El backlog del kernel aumenta la capacidad de conexiones de PostgreSQL?
No. El backlog (somaxconn, tcp_max_syn_backlog) solo mejora la cola de aceptación del sistema durante ráfagas de nuevas conexiones. La capacidad de sesiones simultáneas depende de max_connections y de la eficiencia del pool de conexiones.
¿Necesitas desbloquear la base sin arriesgar datos?
Si el error apareció durante un pico de facturación, un diagnóstico rápido y ajustes en pool, límites y backlog pueden estabilizar el entorno. Hablemos de un plan seguro.
Hablar sobre diagnóstico rápidoVer también
- 502 Bad Gateway intermitente en Docker Compose con Nginx y PHP‑FPM: cómo diagnosticar y corregir timeouts y exceso de conexiones
- Cómo diagnosticar y capturar paquetes por intermitencias de red entre contenedores Docker en Debian
- Cómo detectar y corregir inconsistencias de SKUs duplicados entre WooCommerce y ERP sin perder pedidos
- Cómo resolver el error 'Too many open files' en Linux en servidores PHP‑FPM durante picos de carga