Fix: psql: error: connection to server refused (PostgreSQL)

The Error

You try to connect to PostgreSQL and get:

psql: error: connection to server at "127.0.0.1", port 5432 failed: Connection refused
	Is the server running on that host and accepting TCP/IP connections?

Or one of these variations:

could not connect to server: Connection refused
	Is the server running on that host and accepting TCP/IP connections?
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: No such file or directory
	Is the server running locally and accepting connections on that socket?
psql: error: connection to server at "localhost" (::1), port 5432 failed: Connection refused

All of these mean the same thing: your PostgreSQL client cannot reach the PostgreSQL server.

Why This Happens

PostgreSQL listens for connections on a specific address and port (default: localhost:5432). A “connection refused” error means either nothing is listening at that address, or something is actively blocking the connection.

Common causes:

  • PostgreSQL isn’t running. The service was never started, crashed, or was stopped during an OS update.
  • PostgreSQL is listening on a different address or port. The listen_addresses or port setting in postgresql.conf doesn’t match what your client is connecting to.
  • pg_hba.conf is rejecting the connection. PostgreSQL has its own access control layer that determines which clients are allowed to connect.
  • A firewall is blocking port 5432. iptables, ufw, or Windows Firewall is dropping the connection before it reaches PostgreSQL. This is similar to SSH connection timeout issues caused by firewalls.
  • Docker networking issues. Your app is in a container trying to reach PostgreSQL on localhost, which resolves to the container itself, not the host or another container.
  • The Unix socket file is missing or in the wrong directory. Local connections on Linux/macOS use a socket file, and if it’s missing, the connection fails.
  • max_connections is exhausted. The server is running but has no connection slots left.

Fix 1: Start the PostgreSQL Service

The most common cause. PostgreSQL isn’t running.

Linux (systemd):

sudo systemctl start postgresql

Check the status:

sudo systemctl status postgresql

If it’s not enabled to start on boot:

sudo systemctl enable postgresql

Linux (older init systems):

sudo service postgresql start

macOS (Homebrew):

brew services start postgresql@16

Replace 16 with your installed version. Check which versions are installed:

brew list | grep postgresql

If you installed postgresql (without a version number):

brew services start postgresql

macOS (Postgres.app):

Open the Postgres.app from your Applications folder and click Start.

Windows:

Open Services (Win+R, type services.msc), find postgresql-x64-16 (or your version), right-click, and select Start.

Or from an elevated Command Prompt:

net start postgresql-x64-16

After starting, verify the connection:

psql -U postgres -h localhost -p 5432

Fix 2: Check listen_addresses in postgresql.conf

PostgreSQL may be running but only listening on a specific interface. By default, it listens on localhost only — meaning it rejects connections from other machines (or from Docker containers).

Find your postgresql.conf:

# Linux (Debian/Ubuntu)
sudo cat /etc/postgresql/16/main/postgresql.conf | grep listen_addresses

# Linux (RHEL/Fedora)
sudo cat /var/lib/pgsql/16/data/postgresql.conf | grep listen_addresses

# macOS (Homebrew)
cat /opt/homebrew/var/postgresql@16/postgresql.conf | grep listen_addresses

Or find it from within psql if you can connect locally:

SHOW config_file;

You’ll see something like:

#listen_addresses = 'localhost'

The # means it’s commented out, using the default (localhost). To accept connections from all interfaces:

listen_addresses = '*'

To accept connections from specific IPs only:

listen_addresses = 'localhost,192.168.1.100'

Restart PostgreSQL after changing this:

sudo systemctl restart postgresql

Security note: Setting listen_addresses = '*' means PostgreSQL will accept TCP connections from any network interface. This is safe if pg_hba.conf is properly configured (see Fix 3) and your firewall restricts access. Never expose PostgreSQL to the public internet without proper authentication and firewall rules.

Fix 3: Fix pg_hba.conf (Client Authentication)

Even if PostgreSQL is listening, pg_hba.conf controls which clients are allowed to connect. A misconfigured pg_hba.conf causes this error:

FATAL: no pg_hba.conf entry for host "192.168.1.50", user "myuser", database "mydb"

Find the file:

# Linux (Debian/Ubuntu)
sudo nano /etc/postgresql/16/main/pg_hba.conf

# Linux (RHEL/Fedora)
sudo nano /var/lib/pgsql/16/data/pg_hba.conf

Or from psql:

SHOW hba_file;

Add a line to allow connections from your network:

# TYPE  DATABASE  USER      ADDRESS         METHOD
host    all       all       127.0.0.1/32    scram-sha-256
host    all       all       ::1/128         scram-sha-256
host    all       all       192.168.0.0/16  scram-sha-256

For local Unix socket connections:

local   all       all                       peer

Reload PostgreSQL after editing (no restart required):

sudo systemctl reload postgresql

Auth methods explained:

  • peer — Uses the OS username to authenticate. Only works for local (Unix socket) connections.
  • scram-sha-256 — Password-based authentication (recommended).
  • md5 — Older password-based authentication. Use scram-sha-256 for new setups.
  • trust — No password required. Never use this for remote connections. Only acceptable for local development.

Fix 4: Check the Port

PostgreSQL defaults to port 5432, but another instance or service might be using it, or PostgreSQL may be configured to use a different port.

Check which port PostgreSQL is actually listening on:

# Linux / macOS
sudo ss -tlnp | grep postgres

Or:

sudo netstat -tlnp | grep postgres

You’ll see output like:

tcp  0  0  127.0.0.1:5433  0.0.0.0:*  LISTEN  1234/postgres

If PostgreSQL is on port 5433 (or another port), connect to it explicitly:

psql -U postgres -h localhost -p 5433

To change the port permanently, edit postgresql.conf:

port = 5432

If another process is occupying port 5432, find and stop it (see also Fix: Port 3000 Already in Use for general port conflict debugging):

sudo ss -tlnp | grep 5432

This often happens when you have multiple PostgreSQL versions installed. Each version typically uses an incrementing port (5432, 5433, 5434).

Fix 5: Fix Docker Networking

If your application is inside a Docker container trying to connect to PostgreSQL, localhost inside the container refers to the container itself, not the host machine.

Connecting to PostgreSQL on the host from a container

Docker Desktop (macOS/Windows):

Use host.docker.internal as the hostname:

psql -U postgres -h host.docker.internal -p 5432

Or in your connection string:

postgresql://postgres:password@host.docker.internal:5432/mydb

Linux:

Add --network host to your docker run command, or use the host gateway:

docker run --add-host=host.docker.internal:host-gateway myapp

Then use host.docker.internal as the hostname in your app.

Connecting between containers (docker-compose)

Use the service name as the hostname. In your docker-compose.yml:

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: secret
    ports:
      - "5432:5432"

  app:
    build: .
    environment:
      DATABASE_URL: postgresql://postgres:secret@db:5432/mydb
    depends_on:
      - db

The hostname is db (the service name), not localhost. The ports mapping is only needed if you want to access PostgreSQL from the host machine.

PostgreSQL container isn’t ready yet

If your app container starts before PostgreSQL finishes initializing, the connection fails. Add a health check and depends_on condition:

services:
  db:
    image: postgres:16
    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

Fix 6: Fix the Unix Socket Path

On Linux and macOS, local connections (without -h) use a Unix socket file instead of TCP. If the socket file is missing or in the wrong location, you get:

connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: No such file or directory

Check where PostgreSQL creates the socket:

sudo grep unix_socket_directories /etc/postgresql/16/main/postgresql.conf

The default varies by platform:

  • Debian/Ubuntu: /var/run/postgresql
  • RHEL/Fedora: /var/run/postgresql or /tmp
  • macOS (Homebrew): /tmp

Your client may be looking in a different directory. Specify the socket directory explicitly:

psql -U postgres -h /var/run/postgresql

Or if PostgreSQL uses /tmp:

psql -U postgres -h /tmp

If the socket directory doesn’t exist, create it with the correct permissions:

sudo mkdir -p /var/run/postgresql
sudo chown postgres:postgres /var/run/postgresql
sudo chmod 2775 /var/run/postgresql

Then restart PostgreSQL.

Fix 7: Fix Firewall Rules

A firewall may be silently dropping connections to port 5432.

UFW (Ubuntu):

sudo ufw status
sudo ufw allow 5432/tcp

firewalld (RHEL/Fedora/CentOS):

sudo firewall-cmd --add-port=5432/tcp --permanent
sudo firewall-cmd --reload

iptables:

sudo iptables -A INPUT -p tcp --dport 5432 -j ACCEPT

Windows Firewall:

New-NetFirewallRule -DisplayName "PostgreSQL" -Direction Inbound -Protocol TCP -LocalPort 5432 -Action Allow

Security note: Only open port 5432 to trusted networks. Exposing PostgreSQL to the public internet is a serious security risk. Use a VPN or SSH tunnel for remote access instead.

Still Not Working?

max_connections exhausted

PostgreSQL has a configurable limit on simultaneous connections (default: 100). When all slots are taken, new connections are refused with:

FATAL: sorry, too many clients already

Check current connections:

SELECT count(*) FROM pg_stat_activity;

Check the limit:

SHOW max_connections;

To increase it, edit postgresql.conf:

max_connections = 200

Restart PostgreSQL after changing this. But first, investigate why you’re hitting the limit. A connection leak in your application is a more common problem than the limit being too low. Use a connection pooler like PgBouncer for production workloads.

SSL mode mismatch

If the server requires SSL but your client isn’t using it (or vice versa):

# Force SSL
psql "postgresql://user:pass@host:5432/db?sslmode=require"

# Disable SSL (development only)
psql "postgresql://user:pass@host:5432/db?sslmode=disable"

Common sslmode values:

  • disable — Never use SSL.
  • require — Always use SSL, but don’t verify the server certificate.
  • verify-full — Require SSL and verify the server certificate against a CA. Use this for production.

PostgreSQL crashed and won’t restart

Check the PostgreSQL logs:

# Debian/Ubuntu
sudo tail -50 /var/log/postgresql/postgresql-16-main.log

# RHEL/Fedora
sudo journalctl -u postgresql-16 --no-pager -n 50

# macOS (Homebrew)
tail -50 /opt/homebrew/var/log/postgresql@16.log

Common crash causes:

  • Disk full. PostgreSQL won’t start if it can’t write to the data directory. Free up space and try again.
  • Corrupted PID file. Remove the stale PID file and restart:
sudo rm /var/lib/postgresql/16/main/postmaster.pid
sudo systemctl start postgresql

Warning: Only remove the PID file if you’re certain PostgreSQL is not running. Check with ps aux | grep postgres first.

  • Shared memory issues. On older systems, you may need to increase kernel shared memory limits. Check the logs for could not create shared memory segment and adjust /etc/sysctl.conf accordingly.

Wrong password or user doesn’t exist

These errors are different from “connection refused” but often get mixed up:

FATAL: password authentication failed for user "postgres"
FATAL: role "myuser" does not exist

Reset the postgres user password:

sudo -u postgres psql -c "ALTER USER postgres WITH PASSWORD 'newpassword';"

Create a missing user:

sudo -u postgres createuser --interactive myuser

Cloud-managed PostgreSQL (RDS, Cloud SQL, Azure)

If you’re connecting to a managed database service, “connection refused” usually means:

  • Security group / firewall rules don’t allow your IP address.
  • The instance is stopped or deleted.
  • You’re using the wrong endpoint. Copy the hostname directly from your cloud console.
  • VPC peering or private networking isn’t configured, and public access is disabled.

Check your cloud provider’s console for the exact connection details and ensure your IP is allowed in the security group or authorized networks list.


Related: If you’re troubleshooting Docker container networking issues, see Fix: Docker COPY Failed: File Not Found and Fix: Docker Permission Denied. For Kubernetes connection issues, see Fix: kubectl Connection Refused. If your application can’t read the database connection string from environment variables, see Fix: Environment Variable Is Undefined.

Related Articles