← Back to DevBytes

Fix PostgreSQL 'Connection refused' Error: Complete Troubleshooting Guide

What is the PostgreSQL 'Connection refused' Error?

When connecting to a PostgreSQL database, you may encounter the dreaded Connection refused error. The full error message typically looks like this:

psql: could not connect to server: Connection refused
    Is the server running on host "localhost" (127.0.0.1) and accepting
    TCP/IP connections on port 5432?

Or from an application using a driver like libpq, JDBC, or psycopg2, you might see:

org.postgresql.util.PSQLException: Connection to localhost:5432 refused.
Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.

At its core, the error means that your PostgreSQL client attempted to establish a network connection to the server, but the server did not respond — or actively rejected the connection attempt. This is fundamentally different from authentication failures (where the server responds but denies credentials). Here, no PostgreSQL process is listening on the specified address and port, or a firewall is blocking the traffic before it reaches PostgreSQL.

Understanding this error requires knowing how PostgreSQL accepts connections. PostgreSQL uses a combination of Unix-domain sockets (for local connections on the same machine) and TCP/IP sockets (for remote connections or local connections that explicitly use the -h flag). The Connection refused error occurs exclusively in the TCP/IP pathway — when the operating system's network stack returns a TCP RST (reset) packet because no process is bound to the target port, or when a firewall rule explicitly rejects the connection.

Why This Error Matters

🚀 Deploy your AI agent in 10 minutes

Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.

Try it free →

A Connection refused error is not just an inconvenience — it is a critical indicator that your database infrastructure is either misconfigured or entirely unavailable. Here's why it matters in development and production environments:

Addressing this error correctly ensures your data layer is robust, accessible, and configured according to your environment's requirements — whether that's local development, staging, or production.

Step-by-Step Troubleshooting Guide

The following systematic approach will help you diagnose and fix the Connection refused error. Follow these steps in order — each step builds on the previous one to narrow down the root cause.

Step 1: Verify That PostgreSQL Is Installed and the Service Is Running

The most common cause of this error is simply that PostgreSQL is not running. On Linux systems, check the service status with systemd or the older init script:

# For systemd-based distributions (Ubuntu 16.04+, Debian 8+, CentOS 7+, RHEL 7+)
sudo systemctl status postgresql

# For older init.d systems or to check regardless of init system
ps aux | grep postgres

If the service is not running, start it:

sudo systemctl start postgresql
# or on some distributions
sudo systemctl start postgresql-14  # where 14 is your PostgreSQL major version

On macOS, if installed via Homebrew, check with:

brew services list | grep postgresql
# If not running, start it
brew services start postgresql@14

On Windows, check the Services console (services.msc) for a service named postgresql-x64-14 or similar, and ensure its status is "Running."

If PostgreSQL refuses to start, examine the logs. On Linux, logs are typically at /var/log/postgresql/ or captured by journald:

sudo journalctl -u postgresql -n 50 --no-pager
# or check the PostgreSQL log file directly
sudo tail -50 /var/log/postgresql/postgresql-14-main.log

Common startup failures include incorrect permissions on the data directory, port conflicts, or corrupted configuration files. Resolve any errors reported in the logs before proceeding.

Step 2: Check What Interfaces PostgreSQL Is Listening On

Even if PostgreSQL is running, it may not be listening on the interface you're trying to connect to. PostgreSQL controls this via the listen_addresses parameter in postgresql.conf.

First, locate the configuration file. You can find it by querying the running server (if accessible via a local socket) or by inspecting the data directory:

# Find the config file path (if PostgreSQL is running and accessible via socket)
sudo -u postgres psql -c "SHOW config_file;"

# Or locate it manually on the filesystem
# Common locations:
#   Ubuntu/Debian: /etc/postgresql/14/main/postgresql.conf
#   CentOS/RHEL:   /var/lib/pgsql/14/data/postgresql.conf
#   macOS (Homebrew): /usr/local/var/postgresql@14/postgresql.conf
#   Windows: C:\Program Files\PostgreSQL\14\data\postgresql.conf

Open the file and check the listen_addresses directive:

# Look for this line (it may be commented out)
listen_addresses = 'localhost'

If it is set to 'localhost', PostgreSQL will only accept connections from the same machine via the loopback interface (127.0.0.1 or ::1). Remote connections from other hosts will receive Connection refused. To accept remote connections, change it to:

listen_addresses = '*'    # Listen on all interfaces
# Or specify specific IPs
listen_addresses = '192.168.1.10, 10.0.0.5'

After changing this setting, restart PostgreSQL:

sudo systemctl restart postgresql

Verify the change took effect by checking which addresses PostgreSQL is actually bound to:

sudo netstat -tlnp | grep postgres
# Expected output when listen_addresses = '*':
# tcp  0  0  0.0.0.0:5432  0.0.0.0:*  LISTEN  /postgres
# Expected output when listen_addresses = 'localhost':
# tcp  0  0  127.0.0.1:5432  0.0.0.0:*  LISTEN  /postgres

If you see 0.0.0.0:5432, PostgreSQL is listening on all interfaces. If you see only 127.0.0.1:5432, it's local-only. If you see nothing for TCP, PostgreSQL may be using Unix sockets exclusively — check your configuration again.

Step 3: Verify the Port Number

PostgreSQL defaults to port 5432, but this can be changed. If you're connecting to a non-default port, the Connection refused error occurs because your client is trying the wrong port.

Check the port setting in postgresql.conf:

# In postgresql.conf
port = 5432    # Make sure this matches your connection string

Also verify the actual listening port with netstat (Linux/macOS) or Resource Monitor (Windows):

sudo netstat -tlnp | grep -E 'postgres|5432'
# or use ss
sudo ss -tlnp | grep postgres

If PostgreSQL is running on a non-standard port (say 5433), update your connection strings accordingly:

# psql with explicit port
psql -h localhost -p 5433 -U myuser -d mydb

# Connection string for applications
# PostgreSQL URI format:
postgresql://myuser:mypassword@localhost:5433/mydb

Step 4: Check PostgreSQL's Host-Based Authentication (pg_hba.conf)

Even if PostgreSQL is listening, the pg_hba.conf file controls who can connect. While authentication failures typically produce a different error ("no pg_hba.conf entry for host" or "password authentication failed"), an overly restrictive pg_hba.conf combined with listen_addresses misconfiguration can sometimes result in confusing errors. More importantly, if you've just changed listen_addresses to '*', you must also update pg_hba.conf to allow remote hosts.

Locate pg_hba.conf (usually in the same directory as postgresql.conf) and examine it:

# Typical location: /etc/postgresql/14/main/pg_hba.conf
sudo cat /etc/postgresql/14/main/pg_hba.conf

Add an entry to allow connections from your client's IP address or subnet:

# Allow a specific remote host with MD5 password authentication
host    all             all             192.168.1.100/32        md5

# Allow an entire subnet (e.g., your office network)
host    all             all             10.0.0.0/24            md5

# Allow all remote connections (use with caution — only in development)
host    all             all             0.0.0.0/0               md5

After editing pg_hba.conf, reload PostgreSQL (no restart required for pg_hba.conf changes):

# Reload configuration without restarting
sudo systemctl reload postgresql
# Or via psql if connected locally
sudo -u postgres psql -c "SELECT pg_reload_conf();"

Step 5: Test Local Connection via Unix Socket

If PostgreSQL is running locally but TCP connections are refused, try connecting via the Unix socket (by omitting the -h flag). This bypasses the TCP stack entirely and tests whether the PostgreSQL server itself is functional:

# Connect locally without specifying a host — uses Unix socket
psql -U postgres -d postgres

# If this works, the problem is in the TCP configuration, not the server itself

On Linux, the default Unix socket directory is /var/run/postgresql/. You can verify its existence:

ls -la /var/run/postgresql/.s.PGSQL.5432*
# Or check the configured socket directory
sudo -u postgres psql -c "SHOW unix_socket_directories;"

If Unix socket connections work but TCP connections fail, focus your troubleshooting on listen_addresses, the port number, and firewall rules (covered below).

Step 6: Diagnose Firewall and Network Issues

Firewall rules are a frequent culprit, especially in cloud environments (AWS, GCP, Azure) where security groups and network ACLs control traffic, or on local machines running iptables/nftables or Windows Defender Firewall.

On Linux (iptables/nftables):

# Check iptables rules for port 5432
sudo iptables -L -n | grep 5432

# Check if a firewall service is running
sudo ufw status    # Ubuntu's Uncomplicated Firewall
sudo firewall-cmd --list-all   # CentOS/RHEL firewalld

If a rule is blocking port 5432, add an exception:

# Using ufw (Ubuntu)
sudo ufw allow 5432/tcp

# Using firewalld (CentOS/RHEL)
sudo firewall-cmd --permanent --add-port=5432/tcp
sudo firewall-cmd --reload

# Using raw iptables
sudo iptables -A INPUT -p tcp --dport 5432 -j ACCEPT

On macOS: Check the built-in firewall (usually not an issue for local development):

sudo /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate

On Windows: Open "Windows Defender Firewall with Advanced Security," check inbound rules for port 5432, and create a new rule if necessary:

# PowerShell command to add a firewall rule for PostgreSQL
New-NetFirewallRule -DisplayName "PostgreSQL" -Direction Inbound -Protocol TCP -LocalPort 5432 -Action Allow

Cloud environments: In AWS, check the security group attached to your PostgreSQL instance (RDS or EC2). Ensure an inbound rule exists for port 5432 from your client's IP or CIDR range. In GCP, verify firewall rules under VPC Network > Firewall. In Azure, check Network Security Group rules attached to the subnet or VM.

Test connectivity independently of PostgreSQL using tools like telnet or nc (netcat):

# Test TCP connectivity to the PostgreSQL port
telnet  5432
# Or with netcat
nc -zv  5432

# If these fail with "Connection refused," the issue is network/firewall, not PostgreSQL config

Step 7: Check for Port Conflicts and Resource Exhaustion

Another process may be occupying port 5432, preventing PostgreSQL from binding to it. Alternatively, system resource limits may prevent PostgreSQL from starting or accepting connections.

Check what's listening on port 5432:

sudo lsof -i :5432
# or
sudo ss -tlnp 'sport = :5432'

If another process is using port 5432, either stop that process or configure PostgreSQL to use a different port in postgresql.conf.

Check system limits:

# Check the max number of open file descriptors
ulimit -n
# For the postgres user
sudo -u postgres bash -c 'ulimit -n'

PostgreSQL may fail to start if max_connections exceeds available system resources. The default is typically 100 connections. If you've raised this significantly, ensure your system can handle it. In postgresql.conf:

max_connections = 100   # Adjust based on available RAM and expected workload

Also check disk space — if the data directory's filesystem is full, PostgreSQL may refuse to start or may crash silently:

df -h /var/lib/postgresql  # or wherever your data directory resides

Step 8: Docker and Container-Specific Troubleshooting

In Docker environments, Connection refused errors often stem from networking misconfigurations. Containers have their own network namespace, so localhost inside a container refers to that container, not the host.

Connecting from an application container to a PostgreSQL container:

# Inspect the PostgreSQL container's IP or use Docker's service name
docker inspect  | grep IPAddress

# Better: use Docker Compose service names as hostnames
# In docker-compose.yml:
# services:
#   db:
#     image: postgres:14
#   app:
#     depends_on:
#       - db
#     environment:
#       DATABASE_URL: postgresql://user:password@db:5432/mydb

Connecting from the host machine to a PostgreSQL container:

# Ensure port mapping is correctly configured
docker run -p 5432:5432 --name mypostgres -e POSTGRES_PASSWORD=secret postgres:14

# If you forget -p, the container's port 5432 is NOT exposed to the host
# Check port mappings
docker port mypostgres

Connecting from within the PostgreSQL container itself:

# Exec into the container and connect locally
docker exec -it mypostgres psql -U postgres

Kubernetes-specific: Verify that the Service resource is correctly pointing to the PostgreSQL Pod and that the DNS resolution works from the application Pod:

# From an application pod, test DNS resolution
kubectl exec -it  -- nslookup 

# Test TCP connectivity
kubectl exec -it  -- nc -zv  5432

Also check that the PostgreSQL Pod is in a Running state and not crash-looping:

kubectl get pods -l app=postgres
kubectl logs 

Step 9: Validate Connection String and Driver Configuration

Sometimes the error originates in the application's connection configuration rather than the server. Double-check every component of your connection string or driver configuration:

# Common PostgreSQL connection URI format
postgresql://[user[:password]@][netloc][:port][/dbname][?param1=value1&...]

# Example of a correct URI
postgresql://myuser:mypassword@db.example.com:5432/mydb?sslmode=require

# Common mistakes:
# - Using "http://" instead of "postgresql://"
# - Omitting the port when not using default 5432
# - Using "localhost" when connecting from a different machine
# - Typo in hostname or using an unresolvable hostname

For application code, verify the connection parameters explicitly. Example in Python with psycopg2:

import psycopg2

# Explicit parameters — less error-prone than a URI string
conn = psycopg2.connect(
    host="db.example.com",
    port=5432,
    database="mydb",
    user="myuser",
    password="mypassword",
    connect_timeout=10  # Fail fast — don't hang indefinitely
)

Example in Node.js with the pg library:

const { Client } = require('pg');

const client = new Client({
    host: 'db.example.com',
    port: 5432,
    database: 'mydb',
    user: 'myuser',
    password: 'mypassword',
    connectionTimeoutMillis: 10000,  // 10 seconds
});

await client.connect();

In Java with JDBC:

// jdbc:postgresql://host:port/database
String url = "jdbc:postgresql://db.example.com:5432/mydb";
Properties props = new Properties();
props.setProperty("user", "myuser");
props.setProperty("password", "mypassword");
props.setProperty("connectTimeout", "10");

Connection conn = DriverManager.getConnection(url, props);

Always set a connect_timeout or equivalent to avoid hanging indefinitely when the server is unreachable. A 5-10 second timeout is reasonable for most applications.

Best Practices to Prevent This Error

Preventing the Connection refused error requires proactive configuration management, monitoring, and defensive development patterns. Adopt these practices to minimize the risk of encountering this error in any environment:

Conclusion

The PostgreSQL Connection refused error is a TCP-layer rejection that signals a fundamental disconnect between your client and the database server. Unlike authentication errors, it means no PostgreSQL process is reachable at the address and port you specified — whether because the service is stopped, listening on the wrong interface, blocked by a firewall, or misconfigured in a containerized environment.

By working through the systematic troubleshooting steps outlined in this guide — verifying the service state, checking listen_addresses and port configuration, updating pg_hba.conf, testing via Unix sockets, diagnosing firewalls, inspecting container networking, and validating connection strings — you can isolate the root cause efficiently and apply the precise fix needed. Adopting the best practices of configuration management, health checks, monitoring, and connection pooling will help you avoid this error altogether and build a resilient data access layer that fails gracefully and recovers quickly. With these tools and knowledge, you are well-equipped to handle any Connection refused scenario that arises in your PostgreSQL deployments.

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles