PostgreSQL: "FATAL: sorry, too many clients already" — Causas e Roteiro de Diagnóstico
- Siltech Consult
- há 1 dia
- 3 min de leitura
"Too many clients already" é sintoma, não causa. Pode ser workload real batendo no teto de max_connections, conexões idle in transaction acumuladas por bug na aplicação, ou simplesmente ausência de connection pooling. Antes de sair aumentando max_connections às cegas — o que exige restart do PostgreSQL e mais memória reservada —, vale rodar um diagnóstico rápido para entender qual desses cenários você tem pela frente.
O que o erro significa
O PostgreSQL reserva, na inicialização (parâmetro max_connections, contexto postmaster), um número fixo de slots de conexão. Quando todos os slots estão ocupados, novas tentativas de conexão são rejeitadas com:
FATAL: sorry, too many clients already
Uma parte desses slots é reservada, não somada: por padrão, superuser_reserved_connections = 3 é subtraído do total de max_connections, não adicionado a ele. Ou seja, com max_connections = 100, apenas 97 conexões ficam disponíveis para usuários comuns — as 3 restantes só aceitam superusuário. A partir do PostgreSQL 16, existe também reserved_connections, que reserva slots adicionais para papéis com o privilégio pg_use_reserved_connections (padrão 0, também definido apenas na inicialização).
Diagnóstico passo a passo
1. Confirme o limite configurado e o quanto está sendo usado:
SHOW max_connections;
SELECT count(*) AS conexoes_abertas
FROM pg_stat_activity;
2. Quebre por estado — isso já direciona a causa:
SELECT datname, count(*) AS total,
count(*) FILTER (WHERE state = 'active') AS active,
count(*) FILTER (WHERE state = 'idle') AS idle,
count(*) FILTER (WHERE state = 'idle in transaction') AS idle_in_trans
FROM pg_stat_activity
GROUP BY ROLLUP(1);
Muitas conexões em active: é workload real — carga concorrente genuína batendo no limite.
Muitas em idle in transaction: sinal de alerta forte. É transação aberta pela aplicação e nunca commitada/revertida — geralmente bug de código (conexão pega do pool sem COMMIT/ROLLBACK explícito, ou exceção não tratada que deixa a transação pendurada).
Muitas em idle simples: aplicação abrindo mais conexões do que precisa, sem pooling adequado.
3. Identifique quem está consumindo as conexões:
SELECT usename, application_name, client_addr, count(*)
FROM pg_stat_activity
GROUP BY 1, 2, 3
ORDER BY count(*) DESC;
4. Veja há quanto tempo as sessões idle in transaction estão penduradas:
SELECT pid, usename, application_name, state,
now() - xact_start AS duracao_transacao
FROM pg_stat_activity
WHERE state = 'idle in transaction'
ORDER BY duracao_transacao DESC;
Mitigação imediata (sem restart)
Se o servidor está travado agora, max_connections não pode ser alterado sem restart — é parâmetro de contexto postmaster. A saída imediata é liberar slots derrubando sessões ociosas ou travadas:
-- Encerra a sessão de forma abrupta (equivalente a matar o processo)
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle in transaction'
AND now() - xact_start > interval '10 minutes';
Para pedir que a query em execução seja cancelada de forma mais suave (sem derrubar a conexão), use pg_cancel_backend(pid) em vez de pg_terminate_backend(pid).
Correção estrutural
idle_in_transaction_session_timeout: parâmetro (em milissegundos) que encerra automaticamente sessões paradas em transação aberta além do tempo definido. Evita que o bug de aplicação volte a esgotar as conexões.
statement_timeout: limita o tempo máximo de execução de uma query, útil como cinto de segurança adicional.
Connection pooling (PgBouncer/Pgpool): se o problema é volume real de conexões — muitos processos de aplicação abrindo conexão direta —, a correção correta normalmente não é aumentar max_connections indefinidamente (cada conexão reserva memória do servidor), e sim colocar um pooler na frente do banco, em modo transaction pooling, para multiplexar centenas de conexões de aplicação sobre um número bem menor de conexões reais no PostgreSQL.
Aumentar max_connections: só depois de confirmar que é workload real (não vazamento de transação) e que o servidor tem memória de sobra — cada conexão aberta consome memória do backend, então subir o limite sem revisar shared_buffers/work_mem pode trocar "erro de conexão" por pressão de memória do SO. Observação: o dimensionamento exato de memória por conexão depende de workload e extensões carregadas — não há um número fixo confiável para generalizar aqui; meça no seu ambiente antes de decidir o novo valor.
Validação
Depois de aplicar a correção (timeout de transação ociosa, pooler, ou aumento de max_connections com restart), repita a query de estado do passo 2 e confirme que idle in transaction não volta a crescer sem limite ao longo do tempo — vale monitorar isso continuamente, não só checar uma vez.
Este artigo cobre o roteiro de diagnóstico geral do erro. Se você identificar que o problema é específico de um ambiente gerenciado (RDS/Aurora PostgreSQL, Cloud SQL etc.), verifique se o parâmetro max_connections está sob controle do parameter group do provedor antes de tentar alterá-lo diretamente.

Comentários