How to Fix ECONNREFUSED: Step-by-Step Diagnostic Guide
Fix ECONNREFUSED errors fast. Diagnose whether the process is running, listening on the right port and interface, and check firewalls plus Docker.
How to Fix ECONNREFUSED
ECONNREFUSED is one of the most misread errors in networking. It does not mean the network is down, DNS is broken, or a firewall is silently dropping packets. It means your TCP SYN reached the target host, and the target replied with a RST (reset) packet. Translation: the machine is up, but nothing is listening on that port — or something is listening but actively rejected the connection.
Because the packet round-trip actually completes, ECONNREFUSED is fast (no timeout). That is your biggest clue: this is a service problem, not a network problem. Work through the checks below in order.
Step 1: Is the target process actually running?
Before touching networking, confirm the service you expect to answer is alive.
# Linux with systemd
systemctl status postgresql
systemctl status nginx
# Generic process check
ps aux | grep -i node
pgrep -a postgres
# Docker
docker ps
docker ps -a # includes stopped containers
docker logs <container> --tail 50If the process crashed on startup, you will see it in docker ps -a as Exited or in journalctl -u <service> -n 100. Fix the crash first — nothing else matters until the process stays up.
Step 2: Is it listening on the port you expect?
A running process is not the same as a listening socket. Verify the port is bound.
# Modern Linux (preferred)
ss -tlnp | grep :5432
# Older Linux / BSD
netstat -tlnp | grep :5432
# macOS
lsof -nP -iTCP:5432 -sTCP:LISTEN
# Windows PowerShell
Get-NetTCPConnection -LocalPort 5432 -State ListenNo output means nothing is listening. Check the app's config (wrong port in .env? default overridden?) and its startup logs. A common trap: the process is up but crashed after logging “Server started” — always confirm with ss, not with the app log.
Step 3: Is it listening on the RIGHT interface?
This is the single most common cause of ECONNREFUSED from a remote client. A service can bind to:
127.0.0.1(loopback only) — reachable only from the same host0.0.0.0or::— reachable from any interface- A specific IP like
192.168.1.10— reachable only via that NIC
ss -tlnp
# LISTEN 0 128 127.0.0.1:5432 ← only localhost
# LISTEN 0 128 0.0.0.0:5432 ← all interfaces
# LISTEN 0 128 [::]:5432 ← all IPv6 interfacesIf you see 127.0.0.1:PORT and you are connecting from another machine or a Docker container, the kernel will reject the SYN with RST — producing ECONNREFUSED. Fix it in the app config:
- Postgres:
listen_addresses = '*'inpostgresql.conf - Redis:
bind 0.0.0.0(and set a password!) - Node/Express:
app.listen(3000, '0.0.0.0')instead of the defaultlocalhost - MySQL: comment out
bind-address = 127.0.0.1
Step 4: Firewall or cloud security group
Once the port binds to 0.0.0.0 and you still get ECONNREFUSED locally but a timeout remotely, that is a firewall — different symptom, different fix. But some firewalls (and hosted proxies) issue TCP resets instead of drops, which surfaces as ECONNREFUSED.
# ufw / Debian
sudo ufw status
sudo ufw allow 5432/tcp
# firewalld / RHEL
sudo firewall-cmd --list-all
sudo firewall-cmd --add-port=5432/tcp --permanent && sudo firewall-cmd --reload
# iptables
sudo iptables -L -n -vOn AWS / GCP / Azure, check the instance's security group / firewall rules in the console — inbound rules for the port from your source CIDR.
Step 5: SELinux or AppArmor
On RHEL/CentOS/Fedora, SELinux can block a daemon from binding to a non-standard port even when everything else is correct.
# Check for recent SELinux denials
sudo ausearch -m avc -ts recent
sudo journalctl -t setroubleshoot -n 50
# Allow a service to bind a custom port (example: httpd on 8080)
sudo semanage port -a -t http_port_t -p tcp 8080On Ubuntu, check sudo aa-status and /var/log/syslog for apparmor="DENIED".
Docker-specific traps
Docker networking generates ECONNREFUSED more than any other layer. Three cases dominate:
Container trying to reach a service on the host
Inside a container, localhost is the container itself, not the host. If your app connects to localhost:5432 to reach Postgres running on the host, the container's loopback has nothing listening — instant ECONNREFUSED.
- On Docker Desktop (macOS & Windows): use
host.docker.internalinstead oflocalhost. - On Linux: add
--add-host=host.docker.internal:host-gatewaytodocker run, or use the bridge IP (usually172.17.0.1), or run with--network=host.
Container-to-container on the same host
Containers must share a Docker network and connect by service name, not localhost. In docker-compose.yml, connect from the api service to db:5432 — not localhost:5432.
Port bound to 127.0.0.1 on the host
Publishing with -p 127.0.0.1:5432:5432 binds only to host loopback; remote clients get ECONNREFUSED. Use -p 5432:5432 to bind on all interfaces.
Quick recap
Run the checks in order — process, port, interface, firewall, MAC layer. Nine times out of ten, ECONNREFUSED ends at step 3: the service is bound to 127.0.0.1 and you are connecting from somewhere else. Fix the bind address, restart the service, and move on.