ECONNREFUSED: banco de dados recusando conexão

ECONNREFUSED quer dizer que a máquina de destino respondeu, mas nenhum processo escuta naquele host e porta. Em geral o banco está parado, o endereço está errado ou o servidor só aceita conexões locais.

Atualizado em 7 min de leitura

Objetivos de aprendizado

Depois de ler este artigo, você vai conseguir:

  • Reconhecer o erro ECONNREFUSED em Node.js, Python e no psql
  • Diagnosticar a causa com testes de porta e de endereço
  • Corrigir servidor parado, host errado, bind local e ordem de inicialização
Nesta página

Você sobe a aplicação, ela tenta abrir a conexão com o banco e para na hora com ECONNREFUSED. É um dos erros mais comuns de quem começa a usar PostgreSQL, MySQL, MongoDB ou Redis, e aparece tanto na primeira configuração local quanto no primeiro deploy.

A boa notícia é que o erro é específico. Ele não fala de senha, de permissão nem de consulta: diz que, no endereço e na porta que o seu código usou, nenhum programa aceitou a conexão. Resta descobrir por quê.

ECONNREFUSEDnada escuta aliTeste a portanc ouTest-NetConnectionfechadaO banco está rodando?não: inicie e leia o log1O host está certo?não: nome do serviço (Compose)ou host do provedor2A porta é a do banco?não: corrija na variável3Escuta só em localhost?sim: ajuste o bind e reinicie4
ECONNREFUSED quer dizer que nada escuta naquele host e porta: teste a porta e siga as verificações em ordem.

Como o erro aparece?#

No Node.js, com os drivers pg, mysql2 e redis, a mensagem traz o IP e a porta tentados:

Error: connect ECONNREFUSED 127.0.0.1:5432

No driver oficial do MongoDB, o mesmo problema vem embrulhado no erro de seleção de servidor:

MongoServerSelectionError: connect ECONNREFUSED 127.0.0.1:27017

Se o host for localhost, o Node.js, nas versões recentes, tenta o IPv6 e o IPv4. Quando os dois falham, o erro vira um AggregateError com o código ECONNREFUSED, e cada tentativa fica dentro dele:

AggregateError [ECONNREFUSED]:
  connect ECONNREFUSED ::1:5432
  connect ECONNREFUSED 127.0.0.1:5432

No PostgreSQL, o psql mostra o texto abaixo, e os drivers de Python baseados na libpq (como o psycopg) repetem a mesma mensagem dentro de um OperationalError:

psql: error: connection to server at "127.0.0.1", port 5432 failed: Connection refused
        Is the server running on that host and accepting TCP/IP connections?

A documentação do Node.js define o código assim: nenhuma conexão pôde ser feita porque a máquina de destino a recusou ativamente, o que costuma acontecer ao tentar falar com um serviço inativo no host. A do PostgreSQL reforça: "Connection refused" não quer dizer que o servidor recebeu o pedido e o rejeitou; quer dizer que não havia servidor escutando ali.

O que diferencia ECONNREFUSED de outros erros de conexão?#

Identificar o código certo poupa tempo, porque cada um aponta para uma camada diferente:

Erro O que aconteceu Onde olhar
ECONNREFUSED O host respondeu, mas a porta está fechada Banco parado, porta errada, bind local
ETIMEDOUT Nenhuma resposta dentro do prazo Firewall, rede, IP inalcançável
ENOTFOUND O nome do host não resolveu no DNS Nome do host digitado errado ou inexistente
password authentication failed / Access denied Conectou, mas a credencial falhou Usuário e senha
too many connections Conectou, mas o limite de conexões acabou Pool e conexões abertas

Se o seu erro é o último, o caminho é outro: veja too many connections.

Quais são as causas mais comuns?#

Da mais à menos frequente:

  1. O banco não está rodando. O serviço não foi iniciado, caiu por falta de memória ou de disco, ou o container dele parou.
  2. O host está errado. O código usa localhost, mas o banco está em outra máquina ou em outro container. É a causa número um de "funciona local, quebra em produção".
  3. A porta está errada. As portas padrão são 5432 (PostgreSQL), 3306 (MySQL), 27017 (MongoDB) e 6379 (Redis). Um banco configurado em outra porta recusa a padrão.
  4. O banco só escuta em localhost. O processo está de pé, mas aceita conexões apenas da própria máquina.
  5. A aplicação subiu antes do banco. Em Docker Compose ou num servidor que acabou de reiniciar, o app tenta conectar enquanto o banco ainda inicializa.
  6. IPv6 contra IPv4. localhost resolve para ::1, mas o banco escuta só em 127.0.0.1 (ou o contrário).

Como diagnosticar a causa?#

Primeiro, confirme que a porta está aberta, sem envolver o seu código. No Linux e no macOS, o nc testa qualquer porta, e cada banco tem o seu próprio teste:

bash
nc -vz 127.0.0.1 5432
pg_isready -h 127.0.0.1 -p 5432
redis-cli -h 127.0.0.1 -p 6379 ping
mongosh "mongodb://127.0.0.1:27017" --eval "db.runCommand({ ping: 1 })"

No Windows, use o PowerShell:

powershell
Test-NetConnection 127.0.0.1 -Port 5432

Se a porta está fechada, veja se o processo existe e em qual endereço ele escuta. No Linux:

bash
sudo ss -ltnp | grep -E '5432|3306|27017|6379'

A coluna de endereço local mostra o bind: 127.0.0.1:5432 aceita só conexões locais; 0.0.0.0:5432 ou *:5432 aceita de qualquer interface. Se nada aparece, o banco está parado: olhe o log dele (journalctl -u postgresql, docker logs <container>) para saber por que caiu.

Por último, imprima o que o seu código está usando de fato. Uma variável de ambiente vazia ou com valor antigo explica muitos casos:

bash
node -e "console.log(new URL(process.env.DATABASE_URL).host)"

Como corrigir cada causa?#

Banco parado. Inicie o serviço (sudo systemctl start postgresql, docker start <container>) e descubra por que ele caiu. Se faltou memória ou disco, ele cai de novo enquanto isso não mudar.

Host errado em produção ou em container. Dentro de um container, localhost é o próprio container, não a sua máquina. No Docker Compose, use o nome do serviço como host (db, por exemplo). Em produção, use o host que o provedor do banco informa, sempre por variável de ambiente, nunca fixo no código.

Bind só em localhost. Cada banco tem o seu ajuste, e todos exigem reiniciar o serviço:

  • PostgreSQL: listen_addresses vale localhost por padrão. Para aceitar conexões externas, ajuste em postgresql.conf e libere o acesso em pg_hba.conf.
  • MongoDB: mongod escuta em localhost por padrão. Ajuste net.bindIp no mongod.conf.
  • Redis: o redis.conf padrão traz bind 127.0.0.1 -::1 e o protected mode ligado.
  • MySQL: o padrão de bind_address é * (todas as interfaces), mas confira o arquivo de configuração: o pacote mysql-server do Ubuntu, por exemplo, define bind-address = 127.0.0.1 em /etc/mysql/mysql.conf.d/mysqld.cnf.

Um exemplo no postgresql.conf:

listen_addresses = '10.0.0.5'   # IP da interface privada, não '*' sem firewall

Abrir o banco para a internet sem firewall, senha forte e TLS é um risco sério. Prefira escutar só na rede privada e liberar apenas os IPs da aplicação.

Aplicação antes do banco. No Docker Compose, um depends_on simples só espera o container iniciar, não ficar pronto. Use um healthcheck:

yaml
services:
  db:
    image: postgres:18
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 3s
      retries: 10
  app:
    build: .
    environment:
      DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD}@db:5432/postgres
    depends_on:
      db:
        condition: service_healthy

Fora do Compose, faça o próprio código tentar de novo com espera crescente. Com pg:

js
import pg from "pg";

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

async function connectWithRetry(tries = 5) {
  for (let i = 1; ; i++) {
    const client = new pg.Client({ connectionString: process.env.DATABASE_URL });
    try {
      await client.connect();
      return client;
    } catch (err) {
      if (i >= tries || err.code !== "ECONNREFUSED") throw err;
      const wait = 1000 * 2 ** (i - 1); // 1 s, 2 s, 4 s, 8 s
      console.error(`Banco indisponível (tentativa ${i}/${tries}), nova tentativa em ${wait} ms`);
      await sleep(wait);
    }
  }
}

const db = await connectWithRetry();
const { rows } = await db.query("select now()");
console.log(rows[0]);
await db.end();

O código só repete em ECONNREFUSED: erro de senha ou de host inexistente não melhora esperando. Um pg.Client que falhou não pode ser reaproveitado, por isso o laço cria um novo a cada tentativa.

IPv6 contra IPv4. Troque localhost por 127.0.0.1 na string de conexão, ou faça o banco escutar nos dois endereços.

Como evitar que o erro volte?#

  • Guarde host, porta, usuário e senha numa única variável de conexão, definida em cada ambiente. Veja o que é um arquivo .env.
  • Faça a aplicação falhar com uma mensagem clara se a variável não existir, em vez de cair para localhost.
  • Configure um healthcheck do banco e reinício automático para ele e para o app.
  • Monitore memória e disco do servidor do banco: a falta de um deles é a causa mais comum de queda silenciosa.
  • Se você não quer cuidar de bind, firewall e reinícios, considere uma hospedagem de banco de dados separada da sua máquina.

Como fazer isso na Square Cloud#

A Square Cloud oferece hospedagem de MongoDB, PostgreSQL, MySQL e Redis a partir do plano Standard. Você cria o banco no painel, e ele é provisionado em segundos no mesmo datacenter das aplicações, com latência média de cerca de 1 ms. O plano Hobby não inclui bancos.

O banco não roda dentro do container da aplicação: ele tem host e porta próprios, mostrados no painel junto com a URL de conexão completa. Por isso o erro mais comum ao migrar é a aplicação ainda apontar para localhost ou para a porta padrão do motor. Guarde a URL do painel numa variável de ambiente da aplicação, configurada no painel, na CLI ou na API; a mudança vale no próximo restart, sem rebuild.

O TLS é obrigatório: baixe o certificado no painel e aponte o driver para a CA (no PostgreSQL e no MongoDB, o cliente também apresenta o certificado .pem; no Redis, use rediss://). Como o banco aceita conexões de fora, você pode rodar o teste de porta e o cliente do motor na sua máquina, com o mesmo host, porta e certificado, e separar problema de rede de problema no código.

Você tira snapshots manuais do banco quando quiser, e todo plano com bancos inclui também um snapshot automático diário. Veja os detalhes em hospedagem de bancos de dados.

Hospedagem de bancos

MongoDB, PostgreSQL, MySQL e Redis no mesmo datacenter do app

Saiba mais

Perguntas frequentes

ECONNREFUSED é erro de senha?

Não. A recusa acontece antes de qualquer autenticação: nada está escutando naquela porta. Senha errada gera outra mensagem, como password authentication failed no PostgreSQL ou Access denied no MySQL.

Por que aparece ::1 no erro se eu configurei localhost?

Porque localhost pode resolver para o IPv6 ::1 e para o IPv4 127.0.0.1. O Node.js tenta os dois e, se ambos falham, junta as falhas num AggregateError. Se o banco só escuta em 127.0.0.1, use esse IP no lugar de localhost.

Qual a diferença entre ECONNREFUSED e ETIMEDOUT?

ECONNREFUSED é uma recusa imediata: a máquina existe, mas a porta está fechada. ETIMEDOUT é falta de resposta, comum quando um firewall descarta os pacotes ou o host não é alcançável.

Funciona no meu computador e falha em produção. Por quê?

Quase sempre a variável de conexão em produção ainda aponta para localhost, ou não foi definida e o código usou um valor padrão. Em produção, o banco fica em outro host, que precisa estar na string de conexão.

Próximo artigoMelhor banco de dados para Node.jsPara a maioria dos projetos em Node.js, PostgreSQL é a escolha mais segura. Veja quando usar MySQL, MongoDB, Redis ou SQLite, com drivers e exemplos de código.

Mais em Bancos de dados

Ver todos os 24 artigos