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

Fix ConnectionError: Error 111 connecting to localhost:6379. Connection refused. in Django

This error means Django cannot connect to the configured cache backend, usually Redis or Memcached. Fix it by verifying the cache server is running, checking the connection settings in CACHES, ensuring the correct host and port are configured, and adding a fallback to LocMemCache for development environments.

Reading the Stack Trace

Traceback (most recent call last): File "/app/products/views.py", line 14, in product_list cached = cache.get('product_list') File "/venv/lib/python3.11/site-packages/django_redis/cache.py", line 88, in get return self._get(key, default, version, client) File "/venv/lib/python3.11/site-packages/django_redis/cache.py", line 96, in _get val = client.get(key, default=default) File "/venv/lib/python3.11/site-packages/django_redis/client/default.py", line 228, in get raise ConnectionInterrupted(connection=client, parent=e) File "/venv/lib/python3.11/site-packages/redis/connection.py", line 275, in connect raise ConnectionError(self._error_message(e)) redis.exceptions.ConnectionError: Error 111 connecting to localhost:6379. Connection refused.

Here's what each line means:

Common Causes

1. Redis server not running

The Redis service is not started or has crashed, so Django cannot establish a connection.

# settings.py
CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': 'redis://localhost:6379/0',
    }
}
# Redis not started: sudo systemctl start redis

2. Wrong connection URL in production

The cache settings use localhost in production where Redis runs on a separate host.

# settings.py — same config used in production
CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': 'redis://localhost:6379/0',  # Should be redis://redis-host:6379/0
    }
}

3. Missing IGNORE_EXCEPTIONS option

When Redis goes down, every cache call raises an exception instead of gracefully returning None.

# No fallback configured — cache failures crash the entire site
CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': 'redis://localhost:6379/0',
    }
}

The Fix

Read the Redis URL from an environment variable so production can point to the correct host. Enable IGNORE_EXCEPTIONS so cache failures return None instead of crashing. Add timeouts to prevent slow connections from blocking requests. Provide a LocMemCache fallback for development.

Before (broken)
# settings.py
CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': 'redis://localhost:6379/0',
    }
}
After (fixed)
import os

# settings.py
CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': os.environ.get('REDIS_URL', 'redis://localhost:6379/0'),
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.DefaultClient',
            'IGNORE_EXCEPTIONS': True,  # Gracefully handle Redis downtime
            'SOCKET_CONNECT_TIMEOUT': 5,
            'SOCKET_TIMEOUT': 5,
        },
    }
}

# For development without Redis:
if os.environ.get('USE_LOCMEM_CACHE'):
    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        }
    }

Testing the Fix

import pytest
from unittest.mock import patch
from django.test import TestCase, Client
from django.core.cache import cache


class TestCacheBackend(TestCase):
    def test_cache_set_and_get(self):
        cache.set('test_key', 'test_value', timeout=60)
        assert cache.get('test_key') == 'test_value'

    def test_cache_miss_returns_none(self):
        assert cache.get('nonexistent_key') is None

    def test_view_works_without_cache(self):
        """View should work even if cache is unavailable."""
        with patch.object(cache, 'get', return_value=None):
            client = Client()
            response = client.get('/products/')
            assert response.status_code == 200

    def test_cache_delete(self):
        cache.set('delete_me', 'value', timeout=60)
        cache.delete('delete_me')
        assert cache.get('delete_me') is None

Run your tests:

pytest

Pushing Through CI/CD

git checkout -b fix/redis-cache-connection,git add settings.py,git commit -m "fix: add Redis connection resilience and env-based cache config",git push origin fix/redis-cache-connection

Your CI config should look something like this:

name: CI
on:
  pull_request:
    branches: [main]
jobs:
  test:
    runs-on: ubuntu-latest
    services:
      redis:
        image: redis:7
        ports:
          - 6379:6379
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
          cache: 'pip'
      - run: pip install -r requirements.txt
      - run: pytest --tb=short -q
        env:
          REDIS_URL: redis://localhost:6379/0

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. Run the full test suite locally to confirm cache operations work.
  2. Open a pull request with the cache configuration changes.
  3. Wait for CI checks with Redis service to pass.
  4. Have a teammate review and approve the PR.
  5. Merge to main and verify cache connectivity in staging.

Frequently Asked Questions

BugStack runs the fix through your existing test suite with a real Redis instance, generates tests for cache hit and miss scenarios, and validates graceful degradation before marking it safe to deploy.

BugStack never pushes directly to production. Every fix goes through a pull request with full CI checks, so your team can review it before merging.

Redis is recommended for most Django projects because it supports more data types, persistence, and can also be used for sessions, Celery broker, and Django Channels. Memcached is simpler if you only need basic key-value caching.

Use django-debug-toolbar to see cache hits and misses per request. In production, monitor Redis with redis-cli INFO stats or tools like RedisInsight.