Error "FATAL: remaining connection slots are reserved" en PostgreSQL durante picos de facturación

Por · Publicado el · 8 min de lectura

Pantalla de monitor con interfaz técnica en tonos verdes mostrando gráficos e indicadores desenfocados
Ilustra monitorización de métricas y picos del sistema durante sobrecarga Foto: Tima Miroshnichenko / Pexels

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ápido

Ver también