Redis Connection Refused: How to Fix It (Complete Troubleshooting Guide)

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

Leave a Reply

Your email address will not be published. Required fields are marked *