Guides / OperationalError: connection to server failed: Connection refused
OperationalError: connection to server failed: Connection refused
Django can't reach your database: django.db.utils.OperationalError: connection to server at "localhost" (127.0.0.1), port 5432 failed: Connection refused. The message tells you where Django looked. In production that is almost never the right place.
django.db.utils.OperationalError: connection to server at "localhost" (127.0.0.1), port 5432 failed: Connection refused
Is the server running on that host and accepting TCP/IP connections?
What it means
The TCP connection to the host and port in your DATABASES setting was rejected or never answered. Either nothing listens there, or something in between blocks it. Read the host in the message first. A related message, could not translate host name "db" to address: Name or service not known, means the host name doesn't exist from where the app runs.
Why it happens
- The host is
localhost(or the default empty value). The production settings were never applied, or an environment variable is missing, so Django falls back to the local default. Inside a container,localhostis the container, not your database. - A docker-compose service name used outside compose.
HOST: "db"works in the compose network and nowhere else. - The database isn't reachable from the app. A cloud security group, firewall or VPC route blocks port 5432, or the database isn't publicly reachable and the app is outside its network.
- Postgres isn't listening on that interface. Self-hosted Postgres with
listen_addresses = 'localhost', orpg_hba.confwithout a rule for your app's address. - Wrong port, or a connection pooler such as PgBouncer on a different one.
- The database is down or restarting, for example during a maintenance window.
The fix
Read the whole connection from one environment variable, so production can't silently fall back to a local default. With dj-database-url:
# settings.py
import os
import dj_database_url
DATABASES = {
"default": dj_database_url.config(
env="DATABASE_URL", # no default: fail if it is missing
conn_max_age=60,
)
}
export DATABASE_URL="postgres://USER:PASSWORD@db.example.com:5432/NAME"
Without a library, spell it out and use os.environ[...] so a missing value raises KeyError immediately:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": os.environ["DB_NAME"],
"USER": os.environ["DB_USER"],
"PASSWORD": os.environ["DB_PASSWORD"],
"HOST": os.environ["DB_HOST"],
"PORT": os.environ.get("DB_PORT", "5432"),
}
}
Then test the connection from the same machine or container the app runs in, which is the whole point:
python manage.py dbshell # uses your settings
nc -zv db.example.com 5432 # is the port reachable at all?
psql "$DATABASE_URL" -c "select 1" # does it authenticate?
If nc fails, it's the network: open port 5432 to your app's security group or IP only, never to the whole internet. If nc works and psql fails with an authentication or SSL message, see Postgres: SSL required.
Making it stick in production
- Put database credentials in your platform's secrets store, not in git.
- Keep the database and app in the same region, and in the same private network where you can.
- Run
python manage.py migrate --checkin the release step: it fails fast and loudly when the database isn't reachable. - Set
CONN_MAX_AGEdeliberately; see too many connections.
Or skip it
With Django Cloud you add a managed Postgres database from the dashboard and your app is connected to it, so there is no host or port to get wrong.
pip install djangocloud-cli
djangocloud deploy
Free plans are available for students, AWS Activate startups, open-source, non-profit and research projects. See how Django Cloud compares with other ways to host Django.
Django is a registered trademark of the Django Software Foundation. Django Cloud is not affiliated with or endorsed by it. Found a mistake in this guide? Tell us and we will fix it.