The Error
You run your Node.js app and it crashes โ either immediately or mid-request โ with something like:
Error: connect ECONNREFUSED 127.0.0.1:5432
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1187:16) {
errno: -111,
code: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 5432
}
The port number shifts based on what you're connecting to: 5432 for PostgreSQL, 3306 for MySQL, 6379 for Redis, 27017 for MongoDB, or whatever custom port your service uses. The root cause is always the same: Node.js tried to open a TCP connection to that address and port, and nothing answered.
Root Causes
- The database or service is simply not running.
- The service is running but on a different port than your config expects.
- The service is bound to a different interface (e.g.
::1IPv6 instead of127.0.0.1IPv4). - A firewall or Docker network is blocking the connection.
- Your app started before the database finished booting (race condition in Docker Compose).
- Wrong host/port in your connection string or
.envfile.
Step 1 โ Check Whether the Service Is Running
This fixes the problem 90% of the time.
Linux / macOS
# Check if anything is listening on the target port
sudo ss -tlnp | grep 5432
# or
sudo lsof -i :5432
No output means the service is down. Start it:
# PostgreSQL
sudo systemctl start postgresql
# MySQL / MariaDB
sudo systemctl start mysql
# Redis
sudo systemctl start redis
Windows
netstat -ano | findstr :5432
Nothing listed? Open Services (services.msc) and start the relevant service, or use the application's own start command.
Step 2 โ Verify Your Connection Config
Service is up? Now make sure your app is actually pointing where you think it is. A stale .env or a one-character typo is enough to break the connection.
# .env example
DB_HOST=127.0.0.1
DB_PORT=5432
DB_USER=myuser
DB_PASSWORD=secret
DB_NAME=mydb
Cross-reference with what's actually in your connection code:
// pg (node-postgres)
const { Pool } = require('pg');
const pool = new Pool({
host: process.env.DB_HOST,
port: Number(process.env.DB_PORT),
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
});
Log the resolved values before connecting โ don't guess:
console.log('Connecting to', process.env.DB_HOST, ':', process.env.DB_PORT);
Step 3 โ Check the Bind Address (IPv4 vs IPv6)
Some installations bind only to ::1 (IPv6 loopback), while your app connects to 127.0.0.1 (IPv4). They look the same. They are not โ separate sockets entirely.
sudo ss -tlnp | grep 5432
# If you see *:5432 or :::5432 โ it's IPv6 only
Quick fix: switch your host to localhost and let Node.js resolve it, or use ::1 directly:
DB_HOST=localhost # Node resolves to whichever interface is available
Alternatively, tell PostgreSQL to bind both interfaces by editing postgresql.conf:
listen_addresses = 'localhost' # listens on both 127.0.0.1 and ::1
Step 4 โ Docker Compose Race Condition
Running Node.js and a database together in Docker Compose? Your app container almost certainly starts before the DB is ready. depends_on doesn't help here โ it only waits for the container to start, not for PostgreSQL inside it to finish booting.
The fix is a health check plus condition: service_healthy:
services:
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: secret
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
app:
build: .
depends_on:
db:
condition: service_healthy
environment:
DB_HOST: db
DB_PORT: 5432
Note: in Docker Compose, use the service name (db) as the host, not 127.0.0.1.
Step 5 โ Add Retry Logic in Your App
A single ECONNREFUSED shouldn't kill your entire process. Wire in a retry loop โ it takes about 15 lines and saves a lot of on-call headaches:
const { Pool } = require('pg');
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
async function connectWithRetry(retries = 5, delay = 2000) {
for (let i = 0; i setTimeout(r, delay));
}
}
throw new Error('Could not connect to database after multiple retries');
}
connectWithRetry();
Verification
Before restarting your full app, confirm the connection works at the TCP level:
# Test TCP connectivity directly
nc -zv 127.0.0.1 5432
# Expected: Connection to 127.0.0.1 5432 port [tcp/postgresql] succeeded!
# PostgreSQL: test login
psql -h 127.0.0.1 -p 5432 -U myuser -d mydb -c 'SELECT 1;'
# MySQL:
mysql -h 127.0.0.1 -P 3306 -u myuser -p mydb -e 'SELECT 1;'
# Redis:
redis-cli -h 127.0.0.1 -p 6379 ping
# Expected: PONG
Quick Reference by Port
5432โ PostgreSQL:sudo systemctl start postgresql3306โ MySQL/MariaDB:sudo systemctl start mysql6379โ Redis:sudo systemctl start redis27017โ MongoDB:sudo systemctl start mongod
Tips
Dealing with containers or custom network setups? The Subnet Calculator on ToolCraft lets you check CIDR ranges and confirm that your container IPs fall within the expected network. Runs entirely in the browser โ nothing uploaded.

