Fix OperationalError: could not connect to server: Connection refused in Django
This error occurs when Django cannot connect to the PostgreSQL database server, usually because the server is not running, the host or port is wrong, or network rules block the connection. Fix it by verifying the database server is running, checking DATABASES settings in settings.py, and ensuring network connectivity.
Reading the Stack Trace
Here's what each line means:
- self.connect(): Django's database backend is attempting to establish a connection during the first database query.
- connection = self.Database.connect(**conn_params): psycopg2 tries to connect with the parameters from Django's DATABASES setting and fails.
- Is the server running on host "localhost" (127.0.0.1) and accepting TCP/IP connections on port 5432?: PostgreSQL is either not running, not listening on port 5432, or not accepting connections from this host.
Common Causes
1. PostgreSQL server not running
The database server process is stopped or has crashed, so it cannot accept incoming connections.
# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'myapp_db',
'USER': 'postgres',
'PASSWORD': 'password',
'HOST': 'localhost',
'PORT': '5432',
}
}
# But PostgreSQL is not running: sudo systemctl status postgresql -> inactive
2. Wrong host in Docker environment
In Docker Compose, the database host should be the service name (e.g., 'db'), not 'localhost', because each container has its own network namespace.
# docker-compose.yml uses service name 'db', but settings.py has:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'HOST': 'localhost', # Wrong in Docker
'PORT': '5432',
}
}
3. Environment variable not set
The DATABASE_URL environment variable is not set or is empty, causing Django to use incorrect default connection parameters.
import dj_database_url
DATABASES = {
'default': dj_database_url.config(default='') # Empty string = no connection info
}
The Fix
Read database connection parameters from environment variables so the configuration works across development, Docker, and production environments. Adding CONN_HEALTH_CHECKS ensures Django validates connections before using them.
# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'myapp_db',
'USER': 'postgres',
'PASSWORD': 'password',
'HOST': 'localhost',
'PORT': '5432',
}
}
import os
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DB_NAME', 'myapp_db'),
'USER': os.environ.get('DB_USER', 'postgres'),
'PASSWORD': os.environ.get('DB_PASSWORD', ''),
'HOST': os.environ.get('DB_HOST', 'localhost'),
'PORT': os.environ.get('DB_PORT', '5432'),
'CONN_MAX_AGE': 600,
'CONN_HEALTH_CHECKS': True,
}
}
Testing the Fix
import pytest
from django.db import connections
from django.test.utils import override_settings
@pytest.mark.django_db
def test_database_connection_is_available():
connection = connections['default']
connection.ensure_connection()
assert connection.is_usable()
@pytest.mark.django_db
def test_can_execute_query():
from django.contrib.auth.models import User
count = User.objects.count()
assert isinstance(count, int)
@pytest.mark.django_db
def test_connection_settings_are_configured():
connection = connections['default']
settings = connection.settings_dict
assert settings['ENGINE'] == 'django.db.backends.postgresql'
assert settings['NAME'] != ''
Run your tests:
pytest
Pushing Through CI/CD
git checkout -b fix/database-connection-config,git add src/settings.py,git commit -m "fix: read database config from environment variables",git push origin fix/database-connection-config
Your CI config should look something like this:
name: CI
on:
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: test_db
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: pip install -r requirements.txt
- run: pytest --tb=short
env:
DB_HOST: localhost
DB_PORT: 5432
DB_NAME: test_db
DB_USER: postgres
DB_PASSWORD: postgres
The Full Manual Process: 18 Steps
Here's every step you just went through to fix this one bug:
- Notice the error alert or see it in your monitoring tool
- Open the error dashboard and read the stack trace
- Identify the file and line number from the stack trace
- Open your IDE and navigate to the file
- Read the surrounding code to understand context
- Reproduce the error locally
- Identify the root cause
- Write the fix
- Run the test suite locally
- Fix any failing tests
- Write new tests covering the edge case
- Run the full test suite again
- Create a new git branch
- Commit and push your changes
- Open a pull request
- Wait for code review
- Merge and deploy to production
- Monitor production to confirm the error is resolved
Total time: 30-60 minutes. For one bug.
Or Let bugstack Fix It in Under 2 minutes
Every step above? bugstack does it automatically.
Step 1: Install the SDK
pip install bugstack
Step 2: Initialize
import bugstack
bugstack.init(api_key=os.environ["BUGSTACK_API_KEY"])
Step 3: There is no step 3.
bugstack handles everything from here:
- Captures the stack trace and request context
- Pulls the relevant source files from your GitHub repo
- Analyzes the error and understands the code context
- Generates a minimal, verified fix
- Runs your existing test suite
- Pushes through your CI/CD pipeline
- Deploys to production (or opens a PR for review)
Time from error to fix deployed: Under 2 minutes.
Human involvement: zero.
Try bugstack Free →No credit card. 5-minute setup. Cancel anytime.
Deploying the Fix (Manual Path)
- Verify PostgreSQL is running with pg_isready or systemctl status postgresql.
- Set the required environment variables (DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD).
- Open a pull request with the environment-based configuration.
- Have a teammate review to ensure no credentials are hardcoded.
- Merge to main and verify database connectivity in staging.
Frequently Asked Questions
BugStack verifies the database connection using the configured environment variables, runs migrations, and executes the full test suite against a real database instance.
All fixes go through pull requests with CI that includes a PostgreSQL service container. Connection issues are caught before merging.
In Docker, each container has its own localhost. Use the Docker Compose service name (e.g., 'db') as the HOST instead of 'localhost' so containers can reach each other.
Run pg_isready -h localhost -p 5432 from the command line. It returns 0 if the server is accepting connections, or an error code with a message if not.