Fix "connect ECONNREFUSED 127.0.0.1:5432" β€” Server or Database Connection Refused

intermediate🌐 Networking2026-04-28| Node.js / Python / any backend app connecting to PostgreSQL, MySQL, Redis, or any TCP service on Linux, macOS, Windows

Error Message

Error: connect ECONNREFUSED 127.0.0.1:5432
#networking#econnrefused#backend#database#postgresql#nodejs#docker

What happened

Your app just blew up with:

Error: connect ECONNREFUSED 127.0.0.1:5432

ECONNREFUSED means the OS knocked on that port and got the door slammed in its face. Not a timeout. Not a firewall drop. An active refusal β€” nothing is listening on that port.

The port number tells you which service ghosted you: 5432 = PostgreSQL, 3306 = MySQL, 6379 = Redis, 27017 = MongoDB. Same root cause for all of them β€” the service isn't running, or your app is pointing at the wrong address.

Debug process

Step 1 β€” Is the service actually running?

Nine times out of ten, this is it. Start here before touching anything else.

# Linux / macOS
sudo systemctl status postgresql
sudo systemctl status mysql
sudo systemctl status redis

# Or check what's actually listening on that port
sudo ss -tlnp | grep 5432
sudo lsof -i :5432

No output for that port? The service is down. Jump to Fix 1 below.

Step 2 β€” Is it listening on the right interface?

Trickier than it sounds. PostgreSQL can be running fine but only bound to 127.0.0.1 β€” which means it rejects anything that doesn't come from localhost.

sudo ss -tlnp | grep 5432
# Expected output:
# LISTEN 0 128 127.0.0.1:5432 0.0.0.0:*

0.0.0.0:5432 or :::5432 means it accepts connections on all interfaces. Only 127.0.0.1:5432? Remote connections are dead on arrival β€” local only.

Step 3 β€” Check the connection string in your app

Typos happen. A single wrong character in DB_HOST or DB_PORT sends every connection attempt to a black hole.

# Node.js β€” check your .env or config file
DB_HOST=localhost
DB_PORT=5432

# Python SQLAlchemy
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb

One thing people miss: does localhost actually resolve to 127.0.0.1 on this machine?

ping localhost
# Should resolve to 127.0.0.1 or ::1

On WSL2 or Docker, localhost often resolves differently than you expect β€” it's bitten plenty of developers.

Step 4 β€” Docker? The network is probably the issue

Inside a Docker container, localhost is the container itself β€” not your laptop, not your VM. Your database on the host machine is unreachable via that address.

# Linux β€” use the Docker bridge gateway IP
DB_HOST=172.17.0.1

# Docker Desktop on Mac or Windows β€” this just works
DB_HOST=host.docker.internal

Two containers that need to talk? Put them on the same named Docker network and use the container name as the hostname. Don't rely on IP addresses β€” they change on restart.

Fixes

Fix 1 β€” Start the service

# PostgreSQL
sudo systemctl start postgresql
sudo systemctl enable postgresql   # auto-start on boot

# MySQL / MariaDB
sudo systemctl start mysql

# Redis
sudo systemctl start redis

After starting, confirm it actually came up:

sudo ss -tlnp | grep 5432

Fix 2 β€” Service crashed on start, check the logs

systemctl start can fail silently β€” the command returns with no error, but the service dies within seconds. The logs will tell you why.

journalctl -u postgresql -n 50 --no-pager
# Look for: permission errors, port conflicts, config syntax errors

Three usual suspects: disk is full (run df -h), wrong ownership on the data directory (/var/lib/postgresql/), or another process already grabbed port 5432.

# Find what's squatting on your port
sudo lsof -i :5432

Fix 3 β€” Change the bind address for remote connections

For PostgreSQL, find and edit postgresql.conf:

# Find where the config file lives
psql -U postgres -c 'SHOW config_file;'

# Then change this line:
listen_addresses = '*'    # was: 'localhost'

Don't forget to also update pg_hba.conf to whitelist the remote host, then restart:

sudo systemctl restart postgresql

For MySQL, the setting lives in /etc/mysql/mysql.conf.d/mysqld.cnf:

bind-address = 0.0.0.0    # was: 127.0.0.1

Fix 4 β€” Environment variables not loaded

Classic timing problem: the app launches before .env is sourced, falls back to defaults like localhost:5432, and connects to nothing. Print what the app actually sees at runtime:

# Node.js
console.log('DB:', process.env.DB_HOST, process.env.DB_PORT);

# Python
import os
print(os.getenv('DB_HOST'), os.getenv('DB_PORT'))

Seeing undefined or None? The env file isn't being loaded β€” check your dotenv setup or how the process is being started.

Verification

Before restarting your app, do a raw TCP test to confirm the port is actually reachable:

# Test TCP connectivity directly
nc -zv 127.0.0.1 5432
# Success: Connection to 127.0.0.1 5432 port [tcp/postgresql] succeeded!

# Alternative with curl
curl -v telnet://127.0.0.1:5432

That succeeds but your app still fails? The problem is in the app's config, not the service. Go back to Step 3.

Tips

Debugging Docker bridge networks or VPN routing and staring at an IP you don't recognize? The Subnet Calculator on ToolCraft lets you quickly check which network range an IP belongs to β€” useful for confirming whether an address is local or getting routed somewhere unexpected.

Lessons learned

  • ECONNREFUSED = nothing listening. Debug the service first, not your app code.
  • Run ss -tlnp or lsof -i :PORT before touching anything. Two seconds, saves twenty minutes.
  • Docker's localhost trap catches everyone at least once β€” host.docker.internal is the fix on Mac and Windows.
  • Add a startup health check so your app waits for the database instead of crashing on boot. Tools like wait-for-it handle this in one line.
  • Run systemctl enable on every database service. A server reboot shouldn't mean chasing this error all over again.

Related Error Notes