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:
- Application downtime: Any service relying on PostgreSQL will fail to start or serve requests, causing immediate user-facing outages.
- Deployment failures: Containerized environments (Docker, Kubernetes) often trigger this error when service discovery is misconfigured or when containers start out of order.
- Misleading symptoms: The error can mask deeper issues such as crashed PostgreSQL services, incorrect bind addresses, or exhausted system resources that prevent PostgreSQL from starting properly.
- Security implications: If the error appears after a configuration change, it may indicate that PostgreSQL is intentionally not listening on expected interfaces — which could mean a security hardening step was applied without updating application connection strings.
- Development velocity: Developers lose hours troubleshooting connection errors that could be resolved by systematic diagnosis rather than trial-and-error restarts.
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:
- Use configuration management: Keep
postgresql.confandpg_hba.confunder version control (e.g., in a Git repository alongside your application code). Use infrastructure-as-code tools like Ansible, Terraform, or Chef to provision PostgreSQL with consistent settings across environments. - Set listen_addresses explicitly: Never rely on defaults. In production, explicitly set
listen_addressesto the specific interfaces your application needs. In cloud environments, use'*'cautiously and always pair it with restrictivepg_hba.confrules and security groups. - Implement health checks: In container orchestration platforms, define readiness and liveness probes that verify PostgreSQL is accepting connections. For example, a Kubernetes Pod with a PostgreSQL container should have a TCP socket check on port 5432.
- Monitor PostgreSQL service state: Use system monitoring (Prometheus, Datadog, New Relic) to track whether the PostgreSQL process is running and listening. Set alerts for service failures or unexpected restarts.
- Log and alert on connection failures: In your application, log connection errors with full context (host, port, timestamp, exception message) and trigger alerts so you know about connectivity issues before users report them.
- Use connection pooling: Tools like PgBouncer or Pgpool-II sit between your application and PostgreSQL and can absorb transient connectivity issues, retry connections, and provide a stable endpoint even during brief PostgreSQL restarts.
- Test failover scenarios: If using replication or high-availability setups (Patroni, repmgr), regularly test failover to ensure your applications can connect to the promoted primary without encountering
Connection refusederrors during the transition. - Document environment-specific settings: Maintain a runbook that documents the expected PostgreSQL host, port, and authentication method for each environment (development, staging, production). New team members should be able to connect without guessing.
- Use Docker Compose for local development: Define PostgreSQL as a named service in
docker-compose.ymlwith fixed ports and credentials. This eliminates configuration drift between developer machines and ensures everyone connects to the same well-defined database endpoint. - Prefer Unix sockets for local applications: When your application and PostgreSQL run on the same machine, connect via Unix sockets (by omitting the host parameter or using
/var/run/postgresql). This bypasses TCP entirely and is immune to port conflicts, firewall rules, andlisten_addressesmisconfiguration.
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.