ECONNREFUSED 127.0.0.1:5432: Why Your App Can't Reach the Database
"connect ECONNREFUSED 127.0.0.1:5432" means nothing was listening where your app tried to connect. The causes: database not running, wrong host inside Docker, wrong port, listening on the wrong address, or a firewall. How to find which, plus the related timeout and authentication errors.
Error: connect ECONNREFUSED 127.0.0.1:5432
psql: error: connection to server at "localhost" (::1), port 5432 failed: Connection refused
Connection refused means your app knocked on a door and nobody was there. It reached the computer, but no program was listening on that port. For Postgres the port is usually 5432; for MySQL 3306; for Redis 6379; for MongoDB 27017. The same reasoning applies to all of them.
The good news: it's not a password problem and not a code bug. It's an address problem.
Read the error carefully
127.0.0.1:5432 tells you two things: where it tried (127.0.0.1, which is "this same machine") and which port (5432). (What is localhost?, ports explained) Each cause below is about one of those being wrong.
Cause 1: The database isn't running
The most common one, especially after a restart.
# Postgres installed directly
sudo systemctl status postgresql # Linux
brew services list # macOS with Homebrew
# Postgres in Docker
docker ps # is the container up?
docker compose up -d db
If it's stopped or crashing, start it and check its logs for why.
Cause 2: Your app is in a container, and "localhost" means the container
This catches almost everyone using Docker. Inside a container, localhost refers to that container, not your computer and not the database container.
With Docker Compose, use the service name as the host:
services:
app:
environment:
DATABASE_URL: postgres://postgres:secret@db:5432/app # "db", not localhost
db:
image: postgres:18
If the app runs on your computer and the database in Docker, localhost works only if the port is published (ports: ["127.0.0.1:5432:5432"]). (Docker Compose for local development)
Cause 3: Wrong port
Another Postgres (or a second version) might be on 5432, pushing yours to 5433. Or the connection string has a typo. Check what's actually listening:
sudo ss -ltnp | grep 543 # Linux
lsof -iTCP -sTCP:LISTEN | grep 543 # macOS
(Postgres connection strings explained)
Cause 4: The database only listens on another address
Postgres listens on localhost by default. If your app connects from another machine or container using the server's IP, it's refused. On a server you control, listen_addresses in postgresql.conf and rules in pg_hba.conf control this — but think twice: don't expose your database to the internet. Use a private network or an SSH tunnel. (SSH port forwarding)
Cause 5: IPv6 vs IPv4
Notice ::1 in the second error above. localhost can resolve to the IPv6 address ::1, while your database listens only on IPv4 127.0.0.1. Use 127.0.0.1 explicitly in the connection string, and the problem disappears.
Cause 6: It's starting up
In Docker Compose, the app container often starts before Postgres is ready to accept connections. Add a health check and depends_on: condition: service_healthy, or retry the connection at startup.
Related errors that mean something else
| Error | Means |
|---|---|
ECONNREFUSED |
Reached the machine; nothing listening on that port |
ETIMEDOUT / timeout |
Couldn't reach the machine at all — firewall, wrong IP, network |
ENOTFOUND / getaddrinfo |
The hostname doesn't resolve — typo, or a Docker service name used outside Docker |
password authentication failed |
Connected fine; wrong username or password |
database "x" does not exist |
Connected and logged in; wrong database name |
no pg_hba.conf entry |
Server refused this user/address combination |
too many connections |
Connection limit reached (connection pooling) |
SSL required / self-signed certificate |
Hosted databases need sslmode set correctly |
Getting from "refused" to "password failed" is progress — it means the address is now right.
In production
If it works locally but production shows ECONNREFUSED, the production DATABASE_URL is probably missing or still says localhost. (Why your app works locally but not in production)
The summary
- Connection refused = nothing listening at that host and port.
- Check the database is running first.
- In Docker, use the service name, not
localhost. - Check the port, and try
127.0.0.1instead oflocalhost. - Timeouts, unknown hosts and auth failures are different problems.
EasySpawn servers come with PostgreSQL running alongside your app, with the connection string already set — no ports or Docker networking to get wrong. See how it works or join the waitlist.
Related: Postgres Connection Strings Explained · What Is Localhost? · Docker Compose for Local Development · How to View Your Postgres Database
Keep reading
Postgres Connection Strings Explained: Format, Examples, and Common Errors
What every part of a PostgreSQL connection string (DATABASE_URL) means, how to write one, special characters in passwords, sslmode options, pooled vs direct connections (including Supabase's ports), and how to fix the errors people hit most.
Dates and Time Zones in Apps: How Not to Get Them Wrong
Reminders sent an hour late, bookings on the wrong day, 'yesterday' that's actually today. Why dates are hard, the golden rule (store UTC, display local), ISO 8601, time zones vs offsets, daylight saving traps, and how to check your AI-built app handles them.