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
Here's what each line means:
- File "/app/products/views.py", line 14, in product_list: The view tries to read from the cache before hitting the database, but the cache connection fails.
- File "/venv/lib/python3.11/site-packages/django_redis/cache.py", line 88, in get: django-redis attempts to connect to Redis to retrieve the cached value.
- redis.exceptions.ConnectionError: Error 111 connecting to localhost:6379. Connection refused.: Redis is not running on localhost:6379, or a firewall is blocking the connection.
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.
# settings.py
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://localhost:6379/0',
}
}
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:
- 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)
- Run the full test suite locally to confirm cache operations work.
- Open a pull request with the cache configuration changes.
- Wait for CI checks with Redis service to pass.
- Have a teammate review and approve the PR.
- 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.