top of page

PostgreSQL: "FATAL: sorry, too many clients already" — Causas e Roteiro de Diagnóstico

"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.

 
 
 

Posts recentes

Ver tudo

Comentários


© 2026 por Siltech Consult

  • LinkedIn
bottom of page