Redis Connection Refused: How to Fix It (Complete Troubleshooting Guide)
If you’re staring at a redis.exceptions.ConnectionError: Error 111 connecting to localhost:6379. Connection refused. message, you’re in good company. It’s one of the most common issues developers face when working with Redis, and while the error message itself is straightforward, the underlying cause can be surprisingly elusive.
In this guide, I’ll walk you through every possible reason Redis throws a connection refused error — from the obvious “Redis isn’t running” to edge cases involving IPv6 binding, TLS misconfigurations, and Docker networking quirks. I’ve spent years debugging Redis in production environments, and I’m packing all the hard-won lessons into this article.
Understanding the “Connection Refused” Error
Before we fix anything, let’s understand what “connection refused” actually means at the network level.
When your application tries to connect to Redis, it initiates a TCP handshake to a specific IP and port (typically 6379). A “connection refused” error occurs when the target host is reachable, but no process is listening on that port — or a firewall actively rejects the connection with a TCP RST packet.
This is fundamentally different from:
– Connection timeout — the host is unreachable (firewall drops packets silently)
– Authentication errors — Redis is running but rejects your credentials
– Max clients reached — Redis has hit its connection limit
So when you see “connection refused,” the problem is almost always one of:
1. Redis isn’t running
2. Redis is listening on a different address or port
3. A firewall or network rule is blocking the connection
4. The connection string is wrong
Let’s go through each scenario systematically.
Step 1: Verify Redis Is Actually Running
This sounds obvious, but you’d be amazed how many “complex” Redis issues boil down to the server simply not being started. Let’s check properly.
Check the Redis Process
On Linux or macOS:
ps aux | grep redis-server
You should see output similar to:
redis 1234 0.1 0.5 67890 4567 ? Ssl 10:30 0:15 /usr/bin/redis-server 127.0.0.1:6379
If you don’t see any redis-server process, Redis isn’t running. Start it:
# On Ubuntu/Debian
sudo systemctl start redis-server
# On macOS with Homebrew
brew services start redis
# Or start it manually
redis-server /etc/redis/redis.conf
Check the Service Status
sudo systemctl status redis-server
If the service is inactive (dead) or failed, check the logs:
sudo journalctl -u redis-server -n 50 --no-pager
Common reasons Redis fails to start:
– Port 6379 is already in use by another process
– Misconfigured redis.conf with an invalid directive
– Permission issues on the Redis data directory
– Insufficient memory or vm.overcommit_memory settings
Quick Connectivity Test
Use the Redis CLI to verify the server responds:
redis-cli ping
A healthy Redis instance returns:
PONG
If you get Could not connect to Redis at 127.0.0.1:6379: Connection refused, the server definitely isn’t listening on that address and port.
Step 2: Check Which Address and Port Redis Is Listening On
Here’s where things get interesting. Redis might be running, but it could be bound to a different interface or port than what your application expects.
Inspect Active Listening Ports
sudo ss -tlnp | grep redis
Or with netstat (older systems):
sudo netstat -tlnp | grep redis
Sample output:
LISTEN 0 511 127.0.0.1:6379 0.0.0.0:* users:(("redis-server",pid=1234,fd=6))
Pay close attention to the bind address:
– 127.0.0.1:6379 — Redis only accepts local connections
– 0.0.0.0:6379 — Redis accepts connections from any IP (security risk!)
– :::6379 — Redis is listening on IPv6 only
– 10.0.0.5:6379 — Redis is bound to a specific network interface
If your application connects to a different IP than what Redis is bound to, you’ll get a connection refused error.
Check the Redis Configuration
grep -E "^bind|^port|^protected-mode" /etc/redis/redis.conf
A default configuration looks like:
bind 127.0.0.1 -::1
port 6379
protected-mode yes
The IPv6 Trap
This bit me in production once. Redis was configured with:
bind ::1
This means Redis listens only on IPv6 localhost. My application was connecting to 127.0.0.1 (IPv4), which had no listener. The fix was simple:
bind 127.0.0.1 ::1
Or use localhost in your application connection string, which resolves to the correct stack:
import redis
r = redis.Redis(
host='localhost', # instead of '127.0.0.1'
port=6379,
decode_responses=True
)
Step 3: Verify Your Connection String
A surprising number of connection refused errors come from typos in the connection URL. Double-check every component.
Common Connection String Mistakes
# WRONG: Using redis:// for a TLS-protected Redis instance
r = redis.Redis.from_url("redis://my-redis.example.com:6379")
# RIGHT: Use rediss:// for TLS
r = redis.Redis.from_url("rediss://my-redis.example.com:6379")
// Node.js with ioredis
// WRONG: Forgetting the port
const redis = new Redis('redis://localhost');
// RIGHT: Explicit port
const redis = new Redis('redis://localhost:6379');
Environment Variable Pitfalls
I once spent an hour debugging a connection issue only to discover the environment variable had a trailing space:
# .env file
REDIS_URL=redis://localhost:6379 # ← invisible trailing space
Always trim your environment variables:
import os
redis_url = os.environ.get('REDIS_URL', '').strip()
r = redis.Redis.from_url(redis_url)
Password-Protected Redis
If Redis requires authentication and your connection string omits the password, some clients report a connection error rather than an auth error:
# If Redis has requirepass set
r = redis.Redis.from_url("redis://:yourpassword@localhost:6379")
Step 4: Docker and Container Networking Issues
If you’re running Redis in Docker, connection issues multiply. Let me cover the most common scenarios.
Redis in Docker Not Accessible from Host
When you start Redis in Docker:
docker run --name my-redis -p 6379:6379 -d redis:7
The -p 6379:6379 flag maps the container’s port to your host. If you forgot this flag, Redis is isolated inside the container network:
# Without port mapping — host can't reach it
docker run --name my-redis -d redis:7
# With port mapping — host CAN reach it on localhost:6379
docker run --name my-redis -p 6379:6379 -d redis:7
Docker Compose Service Discovery
In docker-compose.yml, services communicate using service names, not localhost:
version: '3.8'
services:
app:
build: .
environment:
- REDIS_URL=redis://redis:6379 # NOT redis://localhost
depends_on:
- redis
redis:
image: redis:7-alpine
ports:
- "6379:6379"
A critical mistake here: if your app container tries to connect to localhost:6379, it’s looking inside its own container, not the Redis container. Use the service name redis instead.
Test Connectivity Between Containers
# Exec into your app container
docker exec -it my-app sh
# Install redis-cli (Alpine)
apk add redis
# Test the connection
redis-cli -h redis -p 6379 ping
Docker Network Conflicts
Sometimes Docker containers can’t reach each other due to network misconfigurations. Check the network:
docker network inspect myapp_default
Ensure both containers are on the same network and the Redis container has the correct alias.
Step 5: Firewall and Network Configuration
Firewalls silently drop or actively reject connections. Let’s diagnose network-level issues.
Local Firewall (UFW on Ubuntu)
# Check if UFW is blocking Redis
sudo ufw status verbose
# Allow Redis (only if you need remote access — be careful!)
sudo ufw allow 6379/tcp
# Better: allow only from specific IPs
sudo ufw allow from 10.0.0.0/8 to any port 6379
iptables Rules
# List all rules
sudo iptables -L -n -v | grep 6379
# If you find a DROP or REJECT rule, you can remove it
sudo iptables -D INPUT -p tcp --dport 6379 -j DROP
Cloud Provider Security Groups
If Redis runs on AWS, GCP, or Azure, check the security group / firewall rules:
- AWS EC2: Security Group inbound rules must allow port 6379 from your application’s IP
- GCP: Firewall rules must allow TCP 6379
- Azure: Network Security Group must have an inbound security rule for port 6379
Test Port Reachability
# From the machine running your application
nc -zv your-redis-host 6379
# Or using telnet
telnet your-redis-host 6379
A successful connection looks like:
Connection to your-redis-host 6379 port [tcp/*] succeeded!
Step 6: Redis Protected Mode
Redis 3.2.0+ ships with protected mode enabled by default. When Redis is bound to all interfaces (0.0.0.0) without a password, protected mode only accepts local connections and rejects remote ones.
Symptoms
Remote connections fail with:
DENIED Redis is running in protected mode because protected mode is enabled...
But depending on your client library, this might manifest as a connection refused error.
Solution
The proper fix is to set a password:
# In redis.conf
requirepass YourStrongPassword2026!
protected-mode yes
bind 0.0.0.0
Then update your application:
r = redis.Redis(
host='your-redis-host',
port=6379,
password='YourStrongPassword2026!',
decode_responses=True
)
Never disable protected mode without setting a password. Doing so exposes Redis to the internet without authentication.
Step 7: TLS/SSL Configuration Issues
Redis 6.0+ supports TLS natively. If your Redis server requires TLS but your client connects without it, the connection will fail.
Check If TLS Is Enabled
redis-cli -h your-redis-host -p 6379 ping
# Error if TLS is required
redis-cli -h your-redis-host -p 6379 --tls --cert /path/to/client.crt --key /path/to/client.key --cacert /path/to/ca.crt ping
# Works if TLS is required
Python Client TLS Example
import redis
r = redis.Redis(
host='your-redis-host',
port=6379,
ssl=True,
ssl_cert_reqs='required',
ssl_ca_certs='/path/to/ca.crt',
ssl_certfile='/path/to/client.crt',
ssl_keyfile='/path/to/client.key',
decode_responses=True
)
print(r.ping()) # True
Node.js TLS Example
const Redis = require('ioredis');
const redis = new Redis({
host: 'your-redis-host',
port: 6379,
tls: {
ca: fs.readFileSync('/path/to/ca.crt'),
cert: fs.readFileSync('/path/to/client.crt'),
key: fs.readFileSync('/path/to/client.key'),
rejectUnauthorized: true
}
});
Step 8: Connection Pool Exhaustion
Sometimes the error is intermittent — connections work most of the time but occasionally fail. This often points to connection pool exhaustion.
Diagnose with Redis INFO
redis-cli info clients
Output:
# Clients
connected_clients:152
cluster_connections:0
maxclients:10000
If connected_clients is close to maxclients, new connections will be refused.
Check Your Application’s Connection Pool
# Python redis-py — proper pool configuration
import redis
pool = redis.ConnectionPool(
host='localhost',
port=6379,
max_connections=20, # Don't create unlimited connections
socket_timeout=5,
socket_connect_timeout=5,
retry_on_timeout=True
)
r = redis.Redis(connection_pool=pool)
Common Leak Pattern
# BAD: Creating a new connection on every request
def get_user_data(user_id):
r = redis.Redis(host='localhost', port=6379) # ← LEAK!
return r.get(f"user:{user_id}")
# GOOD: Reuse a shared connection
# Initialize once at module level
redis_client = redis.Redis(
host='localhost',
port=6379,
connection_pool=pool
)
def get_user_data(user_id):
return redis_client.get(f"user:{user_id}")
Step 9: Unix Socket Configuration
Redis can listen on a Unix domain socket instead of TCP. If your config has socket enabled but the client connects via TCP (or vice versa), you’ll see connection errors.
Enable Unix Socket in Redis
# In redis.conf
unixsocket /var/run/redis/redis-server.sock
unixsocketperm 700
Connect via Unix Socket
r = redis.Redis(unix_socket_path='/var/run/redis/redis-server.sock')
print(r.ping())
If your Redis instance uses a Unix socket, make sure your application points to the correct socket path and the application process has permission to access it.
Step 10: SELinux and AppArmor
On systems with mandatory access control (SELinux on RHEL/CentOS, AppArmor on Ubuntu), Redis might be blocked from binding to non-standard ports or accessing certain files.
SELinux Diagnosis
# Check if SELinux is blocking Redis
sudo ausearch -m AVC -ts recent | grep redis
# Check Redis process context
ps -eZ | grep redis
Allow Non-Standard Port with SELinux
# If Redis needs to listen on port 6380
sudo semanage port -a -t redis_port_t -p tcp 6380
AppArmor Diagnosis
sudo dmesg | grep redis
sudo apparmor_status
If AppArmor is blocking Redis, check the profile in /etc/apparmor.d/usr.bin.redis-server and adjust the rules accordingly.
Step 11: Kubernetes-Specific Issues
Running Redis on Kubernetes introduces another layer of networking complexity.
Service vs Pod Address
apiVersion: v1
kind: Service
metadata:
name: redis
spec:
selector:
app: redis
ports:
- port: 6379
targetPort: 6379
Your application should connect to the service name:
redis://redis:6379
Not to a pod IP (which changes on restart) or to localhost.
Debug Connectivity
# Exec into your application pod
kubectl exec -it my-app-pod -- sh
# Try to resolve the Redis service
nslookup redis
# Try to connect
redis-cli -h redis -p 6379 ping
If DNS resolution fails, check your CoreDNS configuration and service definitions.
Prevention Tips
Now that we’ve covered how to fix connection issues, let’s talk about preventing them in the first place.
1. Use Connection Health Checks
import redis
import logging
logger = logging.getLogger(__name__)
def create_redis_client():
try:
client = redis.Redis(
host='localhost',
port=6379,
socket_timeout=5,
socket_connect_timeout=5,
retry_on_timeout=True,
health_check_interval=30, # Ping every 30 seconds
decode_responses=True
)
client.ping() # Verify connection on startup
logger.info("Redis connection established successfully")
return client
except redis.ConnectionError as e:
logger.error(f"Failed to connect to Redis: {e}")
raise
2. Implement Circuit Breakers
from circuitbreaker import circuit
import redis
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
@circuit(failure_threshold=5, recovery_timeout=30)
def cache_get(key):
return r.get(key)
# When Redis is down, the circuit breaker prevents
# cascading failures by failing fast
3. Use Connection Pooling Properly
“`python
Singleton pattern for Redis connection pool
import redis
from functools import lru_cache
@lru_cache(maxsize=1)
def get_redis_connection():
pool = redis.ConnectionPool(
host=’localhost’,
port=6379,
max