Erro 'Too many connections' no PostgreSQL durante pico de faturamento — guia prático de diagnóstico e correção
Por Kevin Marcondes · Publicado em · Atualizado em · 8 min de leitura
Erro 'Too many connections' no PostgreSQL durante pico de faturamento: como diagnosticar e resolver. O colapso geralmente combina storms de conexão, transações longas e falta de pooling. Aqui você mede a situação em minutos, aplica contenção segura, corrige causas raiz (pool, timeouts, SQL) e prepara o banco e a aplicação para o próximo fechamento sem sustos.
O que o erro significa e por que explode no pico
O PostgreSQL limita sessões simultâneas por max_connections. Ao atingir o teto, novas conexões falham e a aplicação erra. Em picos de faturamento, tráfego, jobs e relatórios coincidem e multiplicam sessões. Sem pool, cada requisição vira uma conexão. Transações abertas prendem slots e travam filas.
Se suspeitar de jobs concorrendo com o checkout, revise sua janela de execução. Este guia sobre bloqueios e cron detalha impactos e correções: auditar e otimizar jobs cron.
- Tempestade de conexões: múltiplas instâncias/threads abrindo sessões ao mesmo tempo.
- Transações longas e bloqueios: filas crescem, conexões ficam ativas ou presas.
- Jobs e relatórios simultâneos competindo com tráfego de checkout.
- Health checks mal configurados saturando o banco.
Passo 1 — Medir agora: quantas conexões e de onde vêm
Mapeie estados e origens das sessões. Descubra quem consome slots: aplicação, endereço IP, usuário. Isso separa causa de sintoma e orienta as próximas ações. Rode as consultas abaixo no banco afetado.
-- 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';
Passo 2 — Pool de conexões: o amortecedor que falta
Sem pooling, cada requisição abre uma sessão no PostgreSQL. Um pool limita e reutiliza conexões, protegendo o banco de storms. Verifique o pool do app e, se usar PgBouncer, revise limites e modo de pooling. Em picos, o pooling por transação costuma reduzir pressão.
- Prefira pooling por transação para apps web de alta concorrência.
- Dimensione pools por serviço, evitando somar máximos teóricos de todos.
- Aplique timeouts para sessões ociosas e quedas de rede.
; 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
Passo 3 — App sob controle: evite tempestade de conexões
Mesmo com pool, a aplicação pode esgotar sessões ao iniciar múltiplos workers ou em retries agressivos. Ajuste padrões de conexão e backoff. Reduza concorrência durante o pico se necessário. Health checks devem ser leves e não conectar no banco a cada probe.
- Inicialize o pool uma vez por processo; não abra/feche a cada requisição.
- Implemente retries com backoff exponencial e jitter, com limites claros.
- Limite workers simultâneos em horários de pico.
- Tempo de vida de conexão: reciclar periodicamente, sem sincronizar reciclagem.
Passo 4 — Transações longas e SQL pesadas drenam slots
Transações abertas seguram conexões e bloqueios. Relatórios sem índice e N+1 ampliam o tempo preso ao banco. Monitore as consultas mais antigas e foque nas que afetam tabelas quentes. Para acelerar rotas de faturamento, veja este guia de tuning: otimização de consultas PostgreSQL para ERP.
- Encerre sessões travadas e refine índices em rotas de faturamento.
- Evite 'idle in transaction': sempre COMMIT/ROLLBACK.
- Revise jobs de horário comercial e reprograme relatórios 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;
Passo 5 — Ajustar max_connections com segurança (sem adivinhação)
Aumentar max_connections sem planejamento causa OOM e quedas piores. Dimensione memória e prefira pools. Mantenha o banco com número estável de sessões e absorva picos no pool do lado de fora. Use timeouts para evitar conexões eternas.
| Parâmetro | Impacto | Regra prática |
|---|---|---|
| max_connections | Limite de sessões no PostgreSQL | Mantenha moderado e estável; use pool para atender milhares de clientes. |
| shared_buffers | Cache de páginas do banco | Dimensione de acordo com a RAM disponível, evitando competir com SO e cache do filesystem. |
| work_mem | Memória por operação (sort/hash) | Evite valores altos globais; ajuste por sessão/consulta quando necessário. |
| statement_timeout / idle_in_transaction_session_timeout | Evita sessões presas | Defina limites realistas para evitar conexões eternas e filas. |
| Pool (app/PgBouncer) | Amortece picos | Some pools reais e verifique piores cenários de concorrência. |
-- Checar parâmetros atuais
SHOW max_connections;
SHOW shared_buffers;
SHOW work_mem;
SHOW statement_timeout;
SHOW idle_in_transaction_session_timeout;
Passo 6 — Contenção imediata durante o incidente (com cautela)
Estas ações aliviam o colapso enquanto a causa raiz é tratada. Aplicar em produção é arriscado: teste primeiro e limite o escopo ao database/role/aplicação afetada. Foque no tráfego não essencial e em sessões que só ocupam slots.
- Reduza tráfego não essencial (relatórios, integrações menos críticas).
- Cancele consultas lentas; termine sessões zumbis.
- Aplique timeouts temporários para evitar novas filas 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');
Passo 7 — Prevenção para o próximo pico
Consolide aprendizados e crie proteções. Monitore conexões, latência e bloqueios. Teste carga do caminho de faturamento. Isolar relatórios pesados e adotar telemetria e logs estruturados ajuda a antecipar degradações e correlacionar causas.
- Dashboards de conexões ativas, filas e bloqueios com alertas — veja como subir um stack: Prometheus e Grafana com Docker Compose.
- Logs com correlação para rastrear rotas e jobs que saturam conexões: logs estruturados (JSON) e correlação.
- Testes de carga focados em checkout e faturamento.
- Planos de contingência para horários críticos.
Perguntas frequentes
Aumentar o max_connections resolve o erro de vez?
Nem sempre. Pode agravar consumo de memória e latência. O caminho sustentável é manter um número moderado de sessões e usar pool de conexões para absorver picos. Corrija transações longas, consultas lentas e storms na aplicação.
PgBouncer em modo sessão ou transação para apps web?
Para apps web de alta concorrência, o modo por transação costuma funcionar melhor, pois libera conexões rapidamente. O modo por sessão mantém conexões presas durante toda a sessão do cliente, elevando o uso em picos.
Como identificar qual serviço está esgotando conexões?
Use pg_stat_activity para agrupar por application_name, usuário e client_addr. Habilite logs com identificação de aplicação e correlação de requisições. Isso permite mapear rotas e jobs que mais consomem sessões nos horários críticos.
Read replicas ajudam a reduzir ‘Too many connections’?
Replicas aliviam consultas de leitura, mas cada réplica também tem limite de conexões. Sem pool e sem otimizar transações, o problema pode apenas se deslocar. Direcione leituras pesadas para réplicas com pooling adequado.
Por que o erro só aparece no fechamento do mês?
Nesses horários, há picos simultâneos: faturamento, conciliações, relatórios, integrações e aumento de tráfego. Se todos competem e o banco não tem pool, índices e timeouts adequados, o limite de conexões é atingido rapidamente.
Precisa estabilizar o PostgreSQL antes do próximo pico?
Se o erro ‘Too many connections’ apareceu no faturamento, podemos revisar conexões, pool, consultas críticas e timeouts para reduzir o risco de nova queda.
Falar sobre o diagnósticoVeja também
- Como recuperar estatísticas e índices corrompidos no PostgreSQL que deixaram consultas lentas
- API REST com spikes de latência por queries N+1 e GC no PHP — como diagnosticar e corrigir
- Reduzir custos migrando Magento para OpenMage com plano de rollback e testes de aceitação
- Guia prático: como recuperar uma tabela excluída no PostgreSQL usando point-in-time recovery sem downtime