Fix: PostgreSQL Connection Refused – Could Not Connect to Server
Quick Answer
How to fix the PostgreSQL error 'could not connect to server: Connection refused' caused by server not running, wrong host/port, pg_hba.conf, or firewall issues.
The Error
You try to connect to PostgreSQL and get:
psql: error: could not connect to server: Connection refused
Is the server running on host "127.0.0.1" and accepting
TCP/IP connections on port 5432?Or one of these variations:
psql: error: could not connect to server: No such file or directory
Is the server running locally and accepting
connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?FATAL: no pg_hba.conf entry for host "192.168.1.50", user "myuser", database "mydb", SSL offpsql: error: could not connect to server: Connection timed out
Is the server running on host "10.0.0.5" and accepting
TCP/IP connections on port 5432?FATAL: too many connections for role "myuser"FATAL: password authentication failed for user "myuser"psql: error: connection to server at "127.0.0.1", port 5432 failed: server closed the connection unexpectedlyAll of these mean the same underlying problem: your client cannot establish or maintain a connection to the PostgreSQL server. Either PostgreSQL is not running, the connection details are wrong, authentication is misconfigured, or something is blocking the connection at the network level.
Why This Happens
PostgreSQL listens for connections on port 5432 by default. When your client sends a TCP connection request and nothing is listening at that address and port, the operating system responds with a “connection refused” error. When the server is listening but rejects the connection for policy reasons (authentication, too many connections, SSL requirements), you get a different but equally frustrating error.
Common causes:
- PostgreSQL is not running. The service was never started, crashed, or was stopped during a system update or package upgrade. This is the single most common cause.
- Wrong host or port. Your application is trying to connect to
localhost:5432but PostgreSQL is listening on a different interface or port. - Unix socket vs TCP mismatch. PostgreSQL supports both Unix domain sockets and TCP connections. If you are connecting via a socket but PostgreSQL is not creating one at the expected path (or the other way around), the connection fails.
- pg_hba.conf rejecting connections. PostgreSQL uses
pg_hba.conf(Host-Based Authentication) to control which users can connect from which hosts using which authentication methods. A missing or misconfigured entry blocks the connection before it reaches password verification. - listen_addresses not configured. PostgreSQL only listens on
localhostby default. Remote connections are refused unlesslisten_addressesis changed inpostgresql.conf. - Firewall blocking port 5432. A firewall rule is silently dropping or rejecting the connection before it reaches PostgreSQL.
- Docker networking. Your app is running inside a Docker container and
localhostresolves to the container itself, not the host machine or the PostgreSQL container. - max_connections limit reached. PostgreSQL has hit its maximum number of simultaneous connections and is refusing new ones.
- SSL mode mismatch. The server requires SSL but the client is connecting without it, or the client requires SSL but the server does not support it.
Fix 1: Start PostgreSQL
The most common cause by far. PostgreSQL simply is not running.
Linux (systemd):
sudo systemctl start postgresqlOn some distributions, the service name includes the version number:
sudo systemctl start postgresql-16Check the status:
sudo systemctl status postgresqlIf it is not enabled to start on boot:
sudo systemctl enable postgresqlmacOS (Homebrew):
brew services start postgresql@16Check the status:
brew services list | grep postgresqlIf you installed Postgres.app, open the application and click the “Start” button.
Windows:
Open Services (Win+R, type services.msc), find the PostgreSQL service (usually named something like postgresql-x64-16), right-click, and select Start.
Or from an elevated Command Prompt:
net start postgresql-x64-16Verify PostgreSQL is listening:
pg_isreadyIf PostgreSQL is running:
/var/run/postgresql:5432 - accepting connectionsIf it is not running:
localhost:5432 - no responseYou can also check the port directly:
# Linux / macOS
ss -tlnp | grep 5432
# Windows (PowerShell)
netstat -an | findstr 5432If nothing is listening on 5432, PostgreSQL is not running. Check the logs to find out why:
# Linux (Debian/Ubuntu)
sudo tail -50 /var/log/postgresql/postgresql-16-main.log
# Linux (RHEL/Fedora)
sudo tail -50 /var/lib/pgsql/16/data/log/postgresql-*.log
# macOS (Homebrew)
tail -50 /opt/homebrew/var/log/postgresql@16.logCommon startup failures:
- Data directory permissions. PostgreSQL cannot read or write its data directory. Fix with:
sudo chown -R postgres:postgres /var/lib/postgresql/16/main
sudo chmod 700 /var/lib/postgresql/16/main- Corrupt WAL or control file. PostgreSQL refuses to start if critical files are damaged. The log will contain messages like
could not locate a valid checkpoint recordordatabase system is in recovery. In this case, you may need to runpg_resetwalas a last resort (this can cause data loss):
sudo -u postgres pg_resetwal /var/lib/postgresql/16/main- Another process is using port 5432. Check what is using the port:
sudo lsof -i :5432Kill the conflicting process or change the PostgreSQL port in postgresql.conf.
- Stale PID file. If PostgreSQL crashed without cleaning up, a stale
postmaster.pidfile can prevent it from restarting:
# Only do this if you are CERTAIN PostgreSQL is not running
sudo rm /var/lib/postgresql/16/main/postmaster.pid
sudo systemctl start postgresqlFix 2: Check the Host and Port Configuration
Your application may be connecting to the wrong address or port. PostgreSQL defaults to localhost:5432, but this can be changed in postgresql.conf.
Check what PostgreSQL is actually listening on:
sudo -u postgres psql -c "SHOW port;"
sudo -u postgres psql -c "SHOW listen_addresses;"Or look at the config file directly:
grep -E "^(listen_addresses|port)" /etc/postgresql/16/main/postgresql.confA typical config looks like:
listen_addresses = 'localhost'
port = 5432If PostgreSQL is listening on a non-default port, update your application’s connection configuration:
# Python with psycopg2
import psycopg2
conn = psycopg2.connect(
host='127.0.0.1',
port=5433, # match whatever PostgreSQL is actually using
dbname='mydb',
user='myuser',
password='mypassword'
)// Node.js with pg
const { Pool } = require('pg');
const pool = new Pool({
host: '127.0.0.1',
port: 5433,
database: 'mydb',
user: 'myuser',
password: 'mypassword'
});If your connection details come from environment variables (like DATABASE_URL or PGHOST), make sure those variables are actually loaded. A common mistake is forgetting to source a .env file or set variables in your deployment environment. If the variable comes back as undefined, your PostgreSQL client may fall back to defaults that do not match your setup. See Fix: Environment Variable Is Undefined for more on this.
Real-world scenario: You deploy your app to a new server and it can’t connect to PostgreSQL, even though the same connection string works locally. The issue: your local machine connects via Unix socket (triggered by
-h localhost), but the server needs a TCP connection (-h 127.0.0.1). Switching to the IP address fixes it immediately.
Fix 3: Fix Unix Socket vs TCP Connection Issues
PostgreSQL supports two connection methods: Unix domain sockets (local connections only) and TCP/IP. The error message tells you which one is failing.
If you see “No such file or directory” with a socket path:
Is the server running locally and accepting
connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?This means your client is trying to connect via Unix socket, but the socket file does not exist at that path. Either PostgreSQL is not running, or it is creating the socket in a different directory.
Check where the socket actually is:
sudo -u postgres psql -c "SHOW unix_socket_directories;"Common socket paths:
/var/run/postgresql(Debian/Ubuntu)/tmp(macOS Homebrew, some older Linux distributions)/var/pgsql_socket(macOS system PostgreSQL)
If the socket is in a different directory, you have several options:
Option 1: Specify the socket directory when connecting:
psql -h /tmp -U myuser mydbOption 2: Symlink the expected path:
sudo mkdir -p /var/run/postgresql
sudo ln -s /tmp/.s.PGSQL.5432 /var/run/postgresql/.s.PGSQL.5432Option 3: Connect via TCP instead of socket:
psql -h 127.0.0.1 -U myuser mydbUsing -h 127.0.0.1 (an IP address) forces TCP. Using -h localhost may still attempt a Unix socket connection on some systems depending on pg_hba.conf configuration.
Option 4: Change the socket directory in postgresql.conf:
unix_socket_directories = '/var/run/postgresql'Then restart PostgreSQL. This is similar to connection issues you might encounter with other services. If you are also running Redis and hitting similar problems, see Fix: Redis ECONNREFUSED for the Redis-specific version of this troubleshooting process.
Fix 4: Configure pg_hba.conf for Authentication
PostgreSQL uses pg_hba.conf to control client authentication. If your connection is refused with a message like:
FATAL: no pg_hba.conf entry for host "192.168.1.50", user "myuser", database "mydb", SSL offIt means PostgreSQL received your connection but has no rule allowing it.
Find pg_hba.conf:
sudo -u postgres psql -c "SHOW hba_file;"Common locations:
/etc/postgresql/16/main/pg_hba.conf(Debian/Ubuntu)/var/lib/pgsql/16/data/pg_hba.conf(RHEL/Fedora)
Understand the format:
Each line in pg_hba.conf has this structure:
# TYPE DATABASE USER ADDRESS METHOD
local all all peer
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256local= Unix socket connectionshost= TCP/IP connections (with or without SSL)hostssl= TCP/IP connections with SSL onlyhostnossl= TCP/IP connections without SSL
Common fixes:
Allow a specific user from a specific IP:
host mydb myuser 192.168.1.50/32 scram-sha-256Allow a user from an entire subnet:
host mydb myuser 192.168.1.0/24 scram-sha-256Allow all users from any host (use with caution):
host all all 0.0.0.0/0 scram-sha-256After editing pg_hba.conf, reload PostgreSQL (no restart needed):
sudo -u postgres psql -c "SELECT pg_reload_conf();"Or:
sudo systemctl reload postgresqlAuthentication methods:
peer— Uses the operating system username (Unix sockets only). The connecting OS user must match the PostgreSQL user.scram-sha-256— Password-based, the most secure password method.md5— Password-based, older and less secure than scram-sha-256.trust— No authentication at all. Never use in production.reject— Explicitly deny the connection.
A common mistake is having peer authentication for local connections when your application needs password-based authentication. If you see:
FATAL: Peer authentication failed for user "myuser"Change the local line from peer to scram-sha-256:
local all myuser scram-sha-256Or connect via TCP (which uses host rules) instead of Unix socket:
psql -h 127.0.0.1 -U myuser mydbFix 5: Configure listen_addresses for Remote Connections
By default, PostgreSQL only listens on localhost, refusing connections from any other machine. This is the most common cause of “Connection refused” when connecting from a remote host or from a Docker container accessing the host network.
Check the current setting:
sudo -u postgres psql -c "SHOW listen_addresses;"If it returns localhost, PostgreSQL only accepts connections from the local machine.
Edit postgresql.conf:
# Find the file
sudo -u postgres psql -c "SHOW config_file;"Change listen_addresses:
# Listen on all interfaces
listen_addresses = '*'
# Or listen on specific interfaces
listen_addresses = 'localhost, 192.168.1.100'Restart PostgreSQL (a reload is not sufficient for listen_addresses):
sudo systemctl restart postgresqlVerify it is listening on the right interfaces:
ss -tlnp | grep 5432You should see 0.0.0.0:5432 (all interfaces) or the specific IP you configured, instead of 127.0.0.1:5432 (localhost only).
Remember that changing listen_addresses alone is not enough. You also need a matching pg_hba.conf entry (Fix 4) and the firewall must allow traffic on port 5432 (Fix 6).
Fix 6: Configure the Firewall
A firewall may be silently dropping connections to port 5432 before they reach PostgreSQL. This is especially common on cloud servers (AWS, GCP, Azure) where security groups or firewall rules are restrictive by default.
UFW (Ubuntu/Debian):
sudo ufw allow 5432/tcp
sudo ufw reloadOr restrict to a specific subnet:
sudo ufw allow from 192.168.1.0/24 to any port 5432 proto tcpfirewalld (RHEL/Fedora/CentOS):
sudo firewall-cmd --add-port=5432/tcp --permanent
sudo firewall-cmd --reloadiptables:
sudo iptables -A INPUT -p tcp --dport 5432 -j ACCEPTAWS Security Groups:
In the AWS Console, go to your instance’s security group and add an inbound rule for TCP port 5432 from your application’s IP or security group. If you are using RDS, the security group is attached to the RDS instance, not the EC2 instance.
Important: Never expose PostgreSQL port 5432 to the public internet (0.0.0.0/0) without strong authentication and preferably SSL. If you need remote access for development, use SSH tunneling:
ssh -L 5432:127.0.0.1:5432 user@remote-serverThen connect to localhost:5432 on your local machine, and the traffic is forwarded securely through the SSH tunnel. For more on SSH connectivity issues that might prevent this, see Fix: SSH Connection Timed Out.
Fix 7: Fix Docker Networking
If your application runs inside a Docker container and PostgreSQL runs on the host machine or in another container, localhost inside your container refers to the container itself, not the host or other containers. This is one of the most frequent causes of “Connection refused” in containerized environments.
Connecting to PostgreSQL on the host from a container
Docker Desktop (macOS/Windows):
Use the special DNS name host.docker.internal:
postgresql://myuser:mypassword@host.docker.internal:5432/mydbLinux:
docker run --add-host=host.docker.internal:host-gateway myappThen use host.docker.internal as the PostgreSQL host in your application.
Connecting between containers with docker-compose
Use the service name as the hostname, not localhost:
services:
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: myuser
POSTGRES_PASSWORD: mypassword
POSTGRES_DB: mydb
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
app:
build: .
environment:
DATABASE_URL: postgresql://myuser:mypassword@db:5432/mydb
depends_on:
- db
volumes:
pgdata:The hostname is db (the service name), not localhost. Docker’s internal DNS resolves it to the PostgreSQL container’s IP.
PostgreSQL container is not ready yet
If your app starts before PostgreSQL finishes initializing, the connection fails. PostgreSQL takes a few seconds to initialize on first run (creating the database, running initdb). Add a health check so that depends_on waits for PostgreSQL to be truly ready:
services:
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: myuser
POSTGRES_PASSWORD: mypassword
POSTGRES_DB: mydb
healthcheck:
test: ["CMD-SHELL", "pg_isready -U myuser -d mydb"]
interval: 5s
timeout: 3s
retries: 5
app:
build: .
environment:
DATABASE_URL: postgresql://myuser:mypassword@db:5432/mydb
depends_on:
db:
condition: service_healthyFor more on Docker Compose startup and networking problems, see Fix: Docker Compose Up Errors.
Common Mistake: Changing
listen_addressesinpostgresql.confbut forgetting to also add a matchingpg_hba.confentry for the remote IP. Both files must be updated:listen_addressestells PostgreSQL which interfaces to listen on, andpg_hba.conftells it which connections to actually accept.
Fix 8: Handle max_connections Limit
When PostgreSQL hits its max_connections limit, new connections are refused:
FATAL: too many connections for role "myuser"Or:
FATAL: sorry, too many clients alreadyCheck the current limit and active connections
-- Maximum allowed
SHOW max_connections;
-- Currently active
SELECT count(*) FROM pg_stat_activity;
-- Breakdown by user
SELECT usename, count(*) FROM pg_stat_activity GROUP BY usename ORDER BY count DESC;
-- Breakdown by application
SELECT application_name, count(*) FROM pg_stat_activity GROUP BY application_name ORDER BY count DESC;Increase max_connections
In postgresql.conf:
max_connections = 200Then restart PostgreSQL (a reload is not sufficient):
sudo systemctl restart postgresqlNote that each PostgreSQL connection consumes roughly 5-10 MB of RAM. Setting max_connections = 1000 requires significantly more memory. For most applications, the better solution is to use connection pooling.
Use a connection pooler
Instead of increasing max_connections, use a connection pooler like PgBouncer. PgBouncer sits between your application and PostgreSQL, multiplexing many client connections into a smaller number of PostgreSQL connections:
# pgbouncer.ini
[databases]
mydb = host=127.0.0.1 port=5432 dbname=mydb
[pgbouncer]
listen_addr = 127.0.0.1
listen_port = 6432
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
default_pool_size = 20
max_client_conn = 1000Your application connects to PgBouncer on port 6432 instead of PostgreSQL on port 5432. PgBouncer maintains a pool of 20 real PostgreSQL connections and multiplexes up to 1000 client connections through them.
Fix connection leaks
The real problem is often not a low max_connections value but a connection leak in your application. Common causes:
- Not closing connections after use. Always use context managers or connection pools that automatically return connections.
- Long-running idle transactions. A connection stuck in an
idle in transactionstate holds resources. Find them:
SELECT pid, now() - xact_start AS duration, query, state
FROM pg_stat_activity
WHERE state = 'idle in transaction'
ORDER BY duration DESC;Kill long-running idle transactions:
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle in transaction'
AND now() - xact_start > interval '10 minutes';- Serverless function cold starts. Each invocation of an AWS Lambda or similar function may open a new connection without closing the previous one. Use connection pooling (RDS Proxy for AWS, PgBouncer for self-hosted) to manage this.
Fix 9: Fix SSL Mode Configuration
PostgreSQL supports SSL/TLS encryption for connections. If the server and client disagree on SSL requirements, the connection fails.
Common SSL errors:
psql: error: connection to server at "10.0.0.5", port 5432 failed: SSL is not enabled on the serverFATAL: no pg_hba.conf entry for host "192.168.1.50", user "myuser", database "mydb", SSL offCheck if SSL is enabled on the server
SHOW ssl;If it returns off, SSL is disabled. To enable it, edit postgresql.conf:
ssl = on
ssl_cert_file = '/etc/ssl/certs/server.crt'
ssl_key_file = '/etc/ssl/private/server.key'Then restart PostgreSQL.
Client-side SSL modes
PostgreSQL clients support several SSL modes via the sslmode connection parameter:
disable— Never use SSL.allow— Try without SSL first, then with SSL if the server requires it.prefer— Try SSL first, fall back to non-SSL (this is the default for libpq).require— Require SSL but do not verify the server certificate.verify-ca— Require SSL and verify the server certificate against a CA.verify-full— Require SSL, verify the certificate, and check the hostname matches.
Connection string with SSL mode:
postgresql://myuser:mypassword@host:5432/mydb?sslmode=requirePython (psycopg2):
import psycopg2
conn = psycopg2.connect(
host='10.0.0.5',
port=5432,
dbname='mydb',
user='myuser',
password='mypassword',
sslmode='require'
)Node.js (pg):
const { Pool } = require('pg');
const pool = new Pool({
host: '10.0.0.5',
port: 5432,
database: 'mydb',
user: 'myuser',
password: 'mypassword',
ssl: {
rejectUnauthorized: false // set to true in production with proper certs
}
});If pg_hba.conf has hostssl entries but not host entries for your address, connections without SSL will be rejected. Either enable SSL on the client or add a host (non-SSL) entry to pg_hba.conf.
For managed database services like AWS RDS, SSL is enabled by default and the connection string usually requires sslmode=require or higher. Download the RDS CA certificate bundle from AWS and use sslmode=verify-full for production:
postgresql://myuser:mypassword@myinstance.abc123.us-east-1.rds.amazonaws.com:5432/mydb?sslmode=verify-full&sslrootcert=/path/to/rds-combined-ca-bundle.pemStill Not Working?
IPv6 vs IPv4
On some systems, localhost resolves to ::1 (IPv6) instead of 127.0.0.1 (IPv4). PostgreSQL may only be listening on IPv4.
Fix by using 127.0.0.1 explicitly instead of localhost in your connection configuration:
psql -h 127.0.0.1 -U myuser mydbOr configure PostgreSQL to listen on both IPv4 and IPv6:
listen_addresses = 'localhost, ::1'And add IPv6 entries to pg_hba.conf:
host all all ::1/128 scram-sha-256Multiple PostgreSQL versions installed
If you have multiple PostgreSQL versions installed (common on development machines), you might be starting one version but connecting to another. Check which version is running:
sudo -u postgres psql -c "SELECT version();"And make sure the psql client version matches:
psql --versionList all PostgreSQL clusters on Debian/Ubuntu:
pg_lsclustersThis shows the version, cluster name, port, status, and data directory for each installed cluster.
Connection works locally but not remotely
If you can connect from the PostgreSQL server itself but not from another machine, work through this checklist:
- listen_addresses includes the server’s network IP or
*(Fix 5) - pg_hba.conf has a
hostentry for the remote IP (Fix 4) - Firewall allows TCP traffic on port 5432 (Fix 6)
- No NAT or routing issues between the client and server
Test each layer independently:
# From the remote client, test if the port is reachable
nc -zv postgres-server 5432
# Or with telnet
telnet postgres-server 5432If nc shows “Connection refused,” the problem is at the PostgreSQL or OS level. If it shows “Connection timed out,” the problem is at the network/firewall level.
PostgreSQL crashed and won’t restart
Check the PostgreSQL log for the reason:
sudo journalctl -u postgresql --no-pager -n 50Common crash causes:
- Out of memory. PostgreSQL’s shared buffers and work memory settings exceed available RAM, and the OS OOM killer terminates the process. Reduce
shared_buffersandwork_meminpostgresql.conf:
shared_buffers = 256MB
work_mem = 4MB- Disk full. PostgreSQL cannot write WAL or data files. Free up disk space or extend the volume. Check disk usage:
df -h /var/lib/postgresql- Corrupt data directory. If the data directory is corrupted beyond repair, you may need to restore from a backup. Always maintain regular backups with
pg_dumpor continuous archiving withpg_basebackup.
Connection string format reference
PostgreSQL accepts connections via URI format or key-value pairs:
# URI format
postgresql://myuser:mypassword@hostname:5432/mydb?sslmode=require
# Key-value format
host=hostname port=5432 dbname=mydb user=myuser password=mypassword sslmode=require
# Environment variables
export PGHOST=hostname
export PGPORT=5432
export PGDATABASE=mydb
export PGUSER=myuser
export PGPASSWORD=mypasswordIf you are hitting similar issues with the unique constraint errors after finally connecting, see Fix: PostgreSQL duplicate key violates unique constraint. For connection problems with other databases, see Fix: Redis ECONNREFUSED. And if your Docker containers are failing before the connection stage, see Fix: Docker Compose Up Errors.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: PostgreSQL ERROR: deadlock detected
How to fix PostgreSQL deadlock detected error caused by concurrent transactions, conflicting row locks, foreign key locks, and lock ordering issues.
Fix: PostgreSQL permission denied for table (or relation, schema, sequence)
How to fix the PostgreSQL error 'permission denied for table' by granting privileges, fixing default permissions, resolving schema and ownership issues, RLS policies, and role inheritance.
Fix: PostgreSQL ERROR: relation "table_name" does not exist
How to fix the PostgreSQL 'relation does not exist' error caused by schema search_path issues, case sensitivity, wrong database connections, missing migrations, and more.
Fix: PostgreSQL FATAL: role "username" does not exist
How to fix PostgreSQL FATAL role does not exist error caused by missing database roles, peer authentication, wrong usernames, and platform-specific installation defaults.