Error 'Too many connections' en PostgreSQL durante pico de facturación — guía práctica de diagnóstico y corrección

Por · Publicado el · Actualizado el · 8 min de lectura

Panel frontal de racks de servidores con bahías y una mano ajustando un componente
Racks de servidores y almacenamiento — contexto adecuado para incidentes y diagnóstico de base de datos Foto: ColossusCloud / Pixabay

Error 'Too many connections' en PostgreSQL durante pico de facturación: cómo diagnosticar y resolver. El colapso suele combinar tormentas de conexión, transacciones largas y ausencia de pooling. Aquí mides la situación en minutos, aplicas contención segura, corriges las causas raíz (pool, timeouts, SQL) y preparas la base y la aplicación para el próximo cierre sin sobresaltos.

Qué significa el error y por qué explota en el pico

PostgreSQL limita las sesiones simultáneas mediante max_connections. Al alcanzar el límite, las nuevas conexiones fallan y la aplicación lanza errores. En picos de facturación coinciden tráfico, jobs y reportes, y las sesiones se multiplican. Sin pool, cada solicitud se traduce en una conexión. Las transacciones abiertas retienen slots y generan colas.

Si sospechas que jobs compiten con el checkout, revisa su ventana de ejecución. Esta guía sobre bloqueos y cron detalla impactos y correcciones: auditar y optimizar cron jobs.

  • Tormenta de conexiones: múltiples instancias/hilos abriendo sesiones al mismo tiempo.
  • Transacciones largas y bloqueos: las colas crecen; conexiones quedan activas o bloqueadas.
  • Jobs y reportes simultáneos compitiendo con el tráfico de checkout.
  • Health checks mal configurados que saturan la base de datos.

Paso 1 — Medir ahora: cuántas conexiones y de dónde vienen

Mapea estados y orígenes de las sesiones. Descubre quién consume slots: la aplicación, dirección IP o usuario. Esto separa causa de síntoma y orienta las próximas acciones. Ejecuta las consultas siguientes en la base afectada.

-- Sessões por estado
SELECT state, count(*)
FROM pg_stat_activity
WHERE datname = current_database()
GROUP BY 1 ORDER BY 2 DESC;

-- Origem por application_name
SELECT coalesce(application_name, 'unknown') AS app, count(*)
FROM pg_stat_activity
WHERE datname = current_database()
GROUP BY 1 ORDER BY 2 DESC;

-- Clientes que mais abrem conexões
SELECT client_addr, count(*)
FROM pg_stat_activity
WHERE datname = current_database()
GROUP BY 1 ORDER BY 2 DESC;

-- 'idle in transaction' retém slots
SELECT count(*) AS idle_in_tx
FROM pg_stat_activity
WHERE state = 'idle in transaction';

Paso 2 — Pool de conexiones: el amortiguador que falta

Sin pooling, cada petición abre una sesión en PostgreSQL. Un pool limita y reutiliza conexiones, protegiendo la base frente a tormentas. Verifica el pool de la app y, si usas PgBouncer, revisa límites y modo de pooling. En picos, el pooling por transacción suele reducir la presión.

  • Prefiere pooling por transacción para aplicaciones web de alta concurrencia.
  • Dimensiona pools por servicio, evitando sumar máximos teóricos de todos.
  • Aplica timeouts para sesiones ociosas y caídas de red.
; Exemplo de PgBouncer (ilustrativo)
[databases]
mydb = host=127.0.0.1 port=5432 dbname=mydb

[pgbouncer]
max_client_conn = 2000
default_pool_size = 50
reserve_pool_size = 20
pool_mode = transaction
server_idle_timeout = 30
query_timeout = 30
idle_transaction_timeout = 30

Paso 3 — App bajo control: evita la tormenta de conexiones

Incluso con pool, la aplicación puede agotar sesiones al arrancar múltiples workers o con reintentos agresivos. Ajusta parámetros de conexión y backoff. Reduce la concurrencia durante el pico si es necesario. Los health checks deben ser ligeros y no abrir conexión al banco en cada probe.

  • Inicializa el pool una vez por proceso; no abras/cierres por cada petición.
  • Implementa retries con backoff exponencial y jitter, con límites claros.
  • Limita workers simultáneos en horarios de pico.
  • Vida útil de conexión: recicla periódicamente sin sincronizar la reciclación.

Paso 4 — Transacciones largas y SQL pesadas agotan slots

Las transacciones abiertas retienen conexiones y bloqueos. Reportes sin índices y N+1 aumentan el tiempo de ocupación de la base. Monitorea las consultas más antiguas y enfócate en las que afectan tablas calientes. Para acelerar rutas de facturación, consulta esta guía de tuning: optimización de consultas PostgreSQL para ERP.

  • Cierra sesiones bloqueadas y afina índices en rutas de facturación.
  • Evita 'idle in transaction': siempre COMMIT/ROLLBACK.
  • Revisa jobs de horario comercial y reprograma reportes pesados.
-- Top transações antigas e o que aguardam
SELECT pid,
       now() - xact_start AS xact_age,
       state,
       wait_event_type,
       wait_event,
       left(query, 200) AS query
FROM pg_stat_activity
WHERE datname = current_database()
  AND xact_start IS NOT NULL
ORDER BY xact_age DESC
LIMIT 15;

Paso 5 — Ajustar max_connections con seguridad (sin adivinar)

Aumentar max_connections sin planificación puede provocar OOM y caídas peores. Dimensiona la memoria y prefiere pools. Mantén la base con un número estable de sesiones y absorbe picos en el pool externo. Usa timeouts para evitar conexiones eternas.

Parámetro Impacto Regla práctica
max_connections Límite de sesiones en PostgreSQL Manténlo moderado y estable; usa pool para atender miles de clientes.
shared_buffers Caché de páginas de la base Dimensiona según la RAM disponible, evitando competir con el SO y el caché del sistema de archivos.
work_mem Memoria por operación (sort/hash) Evita valores altos globales; ajusta por sesión/consulta cuando sea necesario.
statement_timeout / idle_in_transaction_session_timeout Evita sesiones atascadas Define límites realistas para evitar conexiones eternas y colas.
Pool (app/PgBouncer) Amortigua picos Suma pools reales y verifica peores escenarios de concurrencia.
-- Checar parâmetros atuais
SHOW max_connections;
SHOW shared_buffers;
SHOW work_mem;
SHOW statement_timeout;
SHOW idle_in_transaction_session_timeout;

Paso 6 — Contención inmediata durante el incidente (con cautela)

Estas acciones alivian el colapso mientras se trata la causa raíz. Aplicarlas en producción es arriesgado: prueba antes y limita el alcance al database/role/aplicación afectada. Prioriza tráfico no esencial y sesiones que solo ocupan slots.

  • Reduce tráfico no esencial (reportes, integraciones menos críticas).
  • Cancela consultas lentas; termina sesiones zombis.
  • Aplica timeouts temporales para evitar nuevas colas infinitas.
-- Definir timeouts no DB afetado (temporário)
ALTER DATABASE mydb SET statement_timeout = '30s';
ALTER DATABASE mydb SET idle_in_transaction_session_timeout = '30s';

-- Encerrar sessões ociosas de uma aplicação específica
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'mydb'
  AND application_name = 'checkout'
  AND state IN ('idle','idle in transaction');

Paso 7 — Prevención para el próximo pico

Consolida aprendizajes y crea protecciones. Monitorea conexiones, latencia y bloqueos. Prueba la carga del camino de facturación. Aislar reportes pesados y adoptar telemetría y logs estructurados ayuda a anticipar degradaciones y correlacionar causas.

Preguntas frecuentes

¿Aumentar max_connections resuelve el error definitivamente?

No siempre. Puede aumentar el consumo de memoria y la latencia. El enfoque sostenible es mantener un número moderado de sesiones y usar un pool de conexiones para absorber picos. Corrige transacciones largas, consultas lentas y tormentas desde la aplicación.

¿PgBouncer en modo sesión o transacción para apps web?

Para apps web de alta concurrencia, el modo por transacción suele funcionar mejor, porque libera conexiones rápidamente. El modo por sesión mantiene conexiones ocupadas durante toda la sesión del cliente, incrementando el uso en picos.

¿Cómo identificar qué servicio está agotando conexiones?

Usa pg_stat_activity para agrupar por application_name, usuario y client_addr. Habilita logs con identificación de aplicación y correlación de solicitudes. Eso permite mapear rutas y jobs que más consumen sesiones en horarios críticos.

¿Las réplicas de lectura ayudan a reducir ‘Too many connections’?

Las réplicas alivian consultas de lectura, pero cada réplica también tiene límite de conexiones. Sin pool y sin optimizar transacciones, el problema puede solo desplazarse. Dirige lecturas pesadas a réplicas con pooling adecuado.

¿Por qué el error solo aparece en el cierre de mes?

En esos horarios hay picos simultáneos: facturación, conciliaciones, reportes, integraciones y mayor tráfico. Si todos compiten y la base no tiene pool, índices ni timeouts adecuados, el límite de conexiones se alcanza rápidamente.

¿Necesitas estabilizar PostgreSQL antes del próximo pico?

Si apareció el error ‘Too many connections’ durante facturación, podemos revisar conexiones, pool, consultas críticas y timeouts para reducir el riesgo de una nueva caída.

Hablar sobre el diagnóstico

Ver también