How It Works Features Pricing Blog
Log In Start Free Trial
Django · Python

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

Traceback (most recent call last): File "/app/venv/lib/python3.11/site-packages/django/db/backends/base/base.py", line 289, in ensure_connection self.connect() File "/app/venv/lib/python3.11/site-packages/django/utils/asyncio.py", line 26, in inner return func(*args, **kwargs) File "/app/venv/lib/python3.11/site-packages/django/db/backends/base/base.py", line 270, in connect self.connection = self.get_new_connection(conn_params) File "/app/venv/lib/python3.11/site-packages/django/db/backends/postgresql/base.py", line 275, in get_new_connection connection = self.Database.connect(**conn_params) File "/app/venv/lib/python3.11/site-packages/psycopg2/__init__.py", line 122, in connect conn = _connect(dsn, connection_factory=connection_factory, **kwasync) django.db.utils.OperationalError: 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?

Here's what each line means:

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.

Before (broken)
# settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'myapp_db',
        'USER': 'postgres',
        'PASSWORD': 'password',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}
After (fixed)
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:

  1. Notice the error alert or see it in your monitoring tool
  2. Open the error dashboard and read the stack trace
  3. Identify the file and line number from the stack trace
  4. Open your IDE and navigate to the file
  5. Read the surrounding code to understand context
  6. Reproduce the error locally
  7. Identify the root cause
  8. Write the fix
  9. Run the test suite locally
  10. Fix any failing tests
  11. Write new tests covering the edge case
  12. Run the full test suite again
  13. Create a new git branch
  14. Commit and push your changes
  15. Open a pull request
  16. Wait for code review
  17. Merge and deploy to production
  18. 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:

  1. Captures the stack trace and request context
  2. Pulls the relevant source files from your GitHub repo
  3. Analyzes the error and understands the code context
  4. Generates a minimal, verified fix
  5. Runs your existing test suite
  6. Pushes through your CI/CD pipeline
  7. 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)

  1. Verify PostgreSQL is running with pg_isready or systemctl status postgresql.
  2. Set the required environment variables (DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD).
  3. Open a pull request with the environment-based configuration.
  4. Have a teammate review to ensure no credentials are hardcoded.
  5. 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.