ECONNREFUSED: connection refused — how to fix it
Quick answer: ECONNREFUSED means your app reached the host but nothing was listening on that port — the connection was actively refused. The dependency (Postgres, Redis, an internal API) is down, not started yet, on a different host/port, or unreachable through the network. Verify the service is up and listening, confirm the host and port your app is using, and inside Docker use the service name — not localhost.
What the error looks like
The address in the message tells you exactly what your app failed to reach:
Error: connect ECONNREFUSED 127.0.0.1:5432
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1494:16)
errno: -111, code: 'ECONNREFUSED', address: '127.0.0.1', port: 5432
:5432 is Postgres, :6379 is Redis, :3306 is MySQL. "Refused" is different from "timed out": refused means something answered "nothing's here on this port." That's a strong clue — the host is reachable, the service isn't.
Why connections get refused
The service is down
The database or upstream isn't running — crashed, never started, or still booting when your app connected.
Wrong host or port
A typo, a missing env var defaulting to localhost, or pointing at the wrong port for that service.
localhost inside a container
In Docker, localhost means the container itself — not the host or another container. Use the compose service name.
Bound to the wrong interface
The service listens only on 127.0.0.1, so connections from other hosts/containers are refused. Bind 0.0.0.0.
Diagnose it in three steps
Is anything listening on that port?
# On the host the service should be running on
ss -ltnp | grep 5432
# Probe it directly from where your app runs
nc -zv 127.0.0.1 5432Confirm the host and port your app uses
# Print the actual values your app resolved at runtime
echo "$DATABASE_URL"
# A wrong env var is the #1 cause — don't trust the config file, check the runtime.In Docker, use the service name
Containers talk to each other by service name on the compose network, not localhost:
# docker-compose.yml — app connects to host "db", not "localhost"
services:
app:
environment:
DATABASE_URL: postgres://user:pass@db:5432/app
db:
image: postgres:16Don't start the app before its dependencies
If ECONNREFUSED only happens at startup and then clears, your app raced ahead of its database. Two durable fixes:
- Wait for the dependency to be healthy before starting — a
depends_onwith a healthcheck, or a wait-for script. - Retry with backoff in your connection code, so a brief dependency restart doesn't take your app down with it.
# compose: gate app start on db actually being ready
services:
app:
depends_on:
db: { condition: service_healthy }
db:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 5s
retries: 5
Ordered startup and dependency health, built in
Infraveil is a backend operations control plane that runs on your own servers. Its agent health-checks your services and coordinates how they start, so an app doesn't go live before the database it depends on is ready — the exact race that produces a startup ECONNREFUSED. When a dependency fails, recovery is gated behind your approval and recorded, and you see every service's status in one place instead of SSHing around to find what's down.
Frequently asked questions
What does ECONNREFUSED mean?
Your app reached the host but nothing accepted the connection on that port — it was actively refused. Usually the target service is down, not started yet, or on a different host/port.
ECONNREFUSED vs ETIMEDOUT — what's the difference?
Refused means something answered "nothing is listening here" (host reachable, service not). Timed out means no answer at all — often a firewall, wrong host, or network issue silently dropping packets.
Why does ECONNREFUSED happen in Docker?
Inside a container, localhost refers to that container, not the host or other containers. Connect using the compose service name (e.g. db:5432) on the shared network instead.
How do I fix ECONNREFUSED only on startup?
Your app started before its dependency was ready. Gate startup on a dependency healthcheck (depends_on: condition: service_healthy) and add retry-with-backoff to your connection code.