Redis Connection Refused: Complete Troubleshooting Guide (Connection Refused, Crash, OOM, Permission Denied)
Fix Redis 'Connection refused' errors fast. Covers service crashes, OOM kills, bind config, permission denied, too many connections, and high CPU on Linux.
- Redis 'Connection refused' (ECONNREFUSED 127.0.0.1:6379) almost always means the process is not listening on the expected host/port — start with systemctl status redis and ss -tlnp | grep 6379
- The Linux OOM killer silently terminates redis-server when RAM is exhausted; the Redis crash log stays empty — check dmesg | grep -i 'oom\|killed' immediately after any unexpected stop
- Bind address mismatches and protected-mode yes silently block remote clients even when Redis is fully running — verify redis.conf bind directive and protected-mode before touching firewall rules
- Connection pool exhaustion at the maxclients ceiling causes new ECONNREFUSED under load — monitor with redis-cli INFO clients and raise maxclients in redis.conf
- Quick fix path: (1) restart the service, (2) tail the crash log, (3) check dmesg for OOM kills, (4) verify bind and port config, (5) audit permissions on /var/run/redis and /var/lib/redis
| Method | When to Use | Time | Risk |
|---|---|---|---|
| systemctl restart redis | Service crashed or stopped; no hardware issue | < 1 min | Low — data loss only if persistence disabled |
| Fix bind/protected-mode in redis.conf | Remote clients refused; localhost connects fine | 5 min | Low — test with redis-cli -h <ip> before reload |
| Raise maxclients (CONFIG SET maxclients) | ECONNREFUSED under load; redis-server is running | 2 min | Low — takes effect immediately without restart |
| chown -R redis:redis runtime dirs | Permission denied on socket or PID file at startup | 2 min | Low |
| Set maxmemory + vm.overcommit_memory=1 | OOM kills visible in dmesg; Redis terminated by kernel | 5 min | Medium — tune maxmemory carefully to avoid eviction storms |
| redis-check-aof --fix / redis-check-rdb | Redis exits immediately citing corrupt persistence file | 15–60 min | Medium — may lose writes since last clean snapshot |
| Tune tcp-backlog and net.core.somaxconn | Connection timeouts under burst traffic spikes | 5 min | Low — requires service reload |
Understanding Redis Connection Refused
When your application throws redis.exceptions.ConnectionError: Error 111 connecting to 127.0.0.1:6379. Connection refused. or the Node.js equivalent ECONNREFUSED 127.0.0.1:6379, the TCP handshake to Redis's listening socket failed entirely. The OS rejected the SYN packet because nothing is bound to that address and port — or the process died mid-operation.
This is distinct from ETIMEDOUT (firewalled, packet dropped) or ECONNRESET (connection killed mid-stream). Connection refused is binary: Redis is not there.
Step 1: Confirm Redis Is Actually Running
The fastest two-command diagnostic:
systemctl status redis
ss -tlnp | grep 6379
If systemctl status redis shows Active: failed (Result: exit-code) or Active: inactive (dead), the process is gone. Pull the journal immediately before it rotates:
journalctl -u redis --since '30 minutes ago' --no-pager
Common startup failure messages:
can't open config file /etc/redis/redis.conf: No such file or directory— config path mismatch after package upgradeCreating Server TCP listening socket 127.0.0.1:6379: bind: Address already in use— port held by a zombie redis-server or another processFatal error, can't open config file '/etc/redis.conf'— distro changed default config path- Service starts, writes one log line, then exits — indicates a crash before finishing initialization; see Step 2
Step 2: Read the Redis Crash Log
Redis maintains its own log file independent of systemd. The path is set by the logfile directive in redis.conf; the default on Debian/Ubuntu is /var/log/redis/redis-server.log and on RHEL/CentOS it is /var/log/redis/redis.log.
grep '^logfile' /etc/redis/redis.conf
tail -100 /var/log/redis/redis-server.log
Key patterns and their meanings:
| Log Line | Root Cause |
|---|---|
MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk. |
Disk full or write permission lost on /var/lib/redis |
Can't save in background: fork: Cannot allocate memory |
vm.overcommit_memory=0; kernel refuses fork even with swap available |
Short read or OOM loading DB. Unrecoverable error, aborting now. |
Corrupt RDB or AOF file |
SIGTERM received. Scheduling immediate shutdown. |
Process killed externally (OOM killer, systemd stop timeout) |
WARNING: 32 bit instance detected but no memory limit set! |
32-bit Redis binary without maxmemory — will address space crash |
Accepted 127.0.0.1:XXXXX then immediate shutdown |
Client connected but Redis crashed processing a command |
If the log ends abruptly with no shutdown message, the process was killed by the kernel. Proceed to Step 3.
Step 3: Detect and Fix OOM Kills
The Linux OOM (Out-of-Memory) killer terminates processes without warning when physical RAM and swap are exhausted. Redis is a high-priority target because of its large RSS footprint. The Redis process cannot write to its log before being killed, so the only evidence is in the kernel ring buffer:
dmesg | grep -E 'oom|kill|redis' | tail -40
journalctl -k --since '2 hours ago' | grep -iE 'oom|redis' | tail -40
A confirmed OOM kill looks like:
[1648234.100] Out of memory: Kill process 18432 (redis-server) score 892 or sacrifice child
[1648234.101] Killed process 18432 (redis-server) total-vm:8192000kB, anon-rss:7800000kB, file-rss:0kB
Apply all three mitigations together:
# 1. Set a hard memory cap in redis.conf — leave at least 20% headroom for OS
redis-cli CONFIG SET maxmemory 6gb
redis-cli CONFIG SET maxmemory-policy allkeys-lru
redis-cli CONFIG REWRITE
# 2. Allow the kernel to fork Redis for RDB background saves
echo 'vm.overcommit_memory = 1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
# 3. Disable Transparent Huge Pages (causes RSS bloat after fork-on-write)
echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled
# Persist across reboots via /etc/rc.local or a systemd ExecStartPost unit
For containers, set both --memory on the Docker/Kubernetes resource limit and maxmemory inside Redis. Never rely on only one layer.
Step 4: Fix Bind Address and Protected Mode
Redis 3.2+ ships with protected-mode yes. When this is active and no requirepass is configured, Redis accepts connections only from 127.0.0.1 and ::1. Remote connection attempts receive an immediate disconnect with no log entry — which the OS reports as connection refused from the client's perspective.
Inspect the active configuration:
grep -E '^(bind|protected-mode|port|requirepass)' /etc/redis/redis.conf
Typical output blocking remote access:
bind 127.0.0.1 -::1
protected-mode yes
port 6379
To allow connections from a specific private interface without disabling protected mode:
# In /etc/redis/redis.conf — bind the server's LAN IP alongside localhost
bind 127.0.0.1 192.168.10.50
# Always set a password when binding non-loopback addresses
requirepass YourStrongPasswordHere
# Reload without a full restart
sudo systemctl reload redis
In Docker environments, bind 0.0.0.0 inside the container is common practice, with network policy (security groups, Kubernetes NetworkPolicy) enforcing access control at the infrastructure layer instead.
Step 5: Resolve Permission Denied at Startup
If the journal shows:
Failed to create server unix socket /var/run/redis/redis.sock: Permission denied
or
Failed to open the log file: Permission denied
The redis OS user is missing write access to its runtime, log, or data directories. This commonly happens after a package upgrade that resets ownership, or when directories are created by root:
# Audit current ownership
ls -la /var/run/redis/ /var/log/redis/ /var/lib/redis/
# Restore correct ownership
sudo chown -R redis:redis /var/run/redis /var/log/redis /var/lib/redis
sudo chmod 750 /var/run/redis /var/log/redis /var/lib/redis
# For systemd-managed runtime directories, ensure the unit declares them
sudo systemctl edit redis
# Add these lines under [Service]:
# RuntimeDirectory=redis
# RuntimeDirectoryMode=0755
On SELinux-enforcing systems (RHEL, CentOS, Fedora), also check:
audit2allow -a 2>/dev/null | grep redis
sudo ausearch -c redis --raw | audit2allow -M redis-local
sudo semodule -i redis-local.pp
On AppArmor systems (Ubuntu):
aa-status | grep redis
grep -i redis /var/log/syslog | tail -30
# To temporarily test without AppArmor:
aa-complain /usr/sbin/redis-server
Step 6: Fix Too Many Connections (maxclients Exhaustion)
When Redis hits its maxclients ceiling (default 10000), it rejects new connections immediately. The client sees ECONNREFUSED but Redis logs the event:
Error registering fd event for the new client: Exceeded maxclients limit.
Monitor the live state:
redis-cli INFO clients
# connected_clients:9997
# blocked_clients:412
# maxclients:10000
# rejected_connections:2847
Identify which hosts are holding the most connections:
redis-cli CLIENT LIST | awk -F'[ =:]' '{for(i=1;i<NF;i++) if($i=="addr") print $(i+1)}' | sort | uniq -c | sort -rn | head -20
Find idle connections older than 1 hour (likely leaked):
redis-cli CLIENT LIST | awk -F'[ =]' '{for(i=1;i<=NF;i++) if($i=="idle" && $(i+1)+0 > 3600) print}'
Fix in priority order:
- Fix connection pool configuration in your application — set a reasonable
max_connectionsand ensure connections are returned to the pool after use - Enable TCP keepalive: add
tcp-keepalive 60to redis.conf — this evicts connections that have gone away without a proper FIN - Raise the ceiling temporarily:
redis-cli CONFIG SET maxclients 25000 - Kill idle connections:
redis-cli CLIENT KILL ID <id>for confirmed leaks
Step 7: Diagnose High CPU and Latency
Redis appearing slow or unresponsive without ECONNREFUSED is often misreported as 'connection refused' by monitoring tools. Use the built-in slowlog:
# Show commands that took longer than the configured threshold
redis-cli SLOWLOG GET 25
# Measure current round-trip latency (run for 10 seconds)
redis-cli --latency -i 1
# Check last RDB save timing — fork can cause latency spikes
redis-cli INFO stats | grep -E 'rdb_last_bgsave_time_sec|rdb_current_bgsave_time_sec'
The most common CPU offenders:
KEYS *in application code — replace withSCAN 0 COUNT 100iterativelySMEMBERSon sets with millions of members — paginate withSSCAN- Unthrottled
MONITORleft running in production (captures every command) - Lua scripts with large iteration loops
Set a useful slowlog threshold in redis.conf:
slowlog-log-slower-than 10000
slowlog-max-len 1024
Step 8: Recover from a Corrupted RDB or AOF File
If Redis exits immediately on startup with Short read or OOM loading DB, the persistence file on disk is corrupted — often from a power loss or disk error during a background save.
# Locate the persistence files
grep -E '^(dir|dbfilename|appendfilename)' /etc/redis/redis.conf
# Attempt AOF repair (creates a .bak of the original)
sudo redis-check-aof --fix /var/lib/redis/appendonly.aof
# Verify RDB integrity (read-only, no fix option)
sudo redis-check-rdb /var/lib/redis/dump.rdb
# If both are unrecoverable, start fresh (data loss — restore from backup)
sudo systemctl stop redis
sudo mv /var/lib/redis/dump.rdb /var/lib/redis/dump.rdb.corrupt.bak
sudo mv /var/lib/redis/appendonly.aof /var/lib/redis/appendonly.aof.corrupt.bak
sudo systemctl start redis
Always maintain off-instance backups (S3, GCS, or a replica promoted to standalone) for production Redis instances carrying persistent data.
Frequently Asked Questions
#!/usr/bin/env bash
# Redis Full Diagnostic Script
# Run as root or with sudo. Covers: connection refused, crash, OOM,
# permission denied, too many connections, high CPU, corrupt persistence.
REDIS_CONF="/etc/redis/redis.conf"
REDIS_LOG="/var/log/redis/redis-server.log"
REDIS_DATA="/var/lib/redis"
REDIS_PORT=6379
SEP="$(printf '%0.s=' {1..60})"
echo "$SEP"
echo "=== 1. Service Status ==="
echo "$SEP"
systemctl status redis --no-pager -l 2>/dev/null \
|| systemctl status redis-server --no-pager -l 2>/dev/null \
|| echo "[WARN] Could not determine service status"
echo ""
echo "$SEP"
echo "=== 2. Process Check ==="
echo "$SEP"
pgrep -a redis-server || echo "[WARN] No redis-server process running"
echo ""
echo "$SEP"
echo "=== 3. Port Binding (expecting ${REDIS_PORT}) ==="
echo "$SEP"
ss -tlnp | grep ":${REDIS_PORT}" || echo "[WARN] Nothing listening on port ${REDIS_PORT}"
echo ""
echo "$SEP"
echo "=== 4. OOM Kill Check (last 2 hours) ==="
echo "$SEP"
dmesg 2>/dev/null | grep -E 'oom|[Kk]ill.*redis|redis.*[Kk]ill' | tail -20 \
|| journalctl -k --since '2 hours ago' 2>/dev/null | grep -iE 'oom|redis' | tail -20 \
|| echo "[INFO] No OOM events found in ring buffer"
echo ""
echo "$SEP"
echo "=== 5. Redis Crash Log (last 80 lines) ==="
echo "$SEP"
if [ -f "$REDIS_LOG" ]; then
tail -80 "$REDIS_LOG"
else
# Try to find the log path from the config
LOGPATH=$(grep '^logfile' "$REDIS_CONF" 2>/dev/null | awk '{print $2}' | tr -d '"')
[ -n "$LOGPATH" ] && tail -80 "$LOGPATH" || echo "[WARN] Could not locate Redis log file"
fi
echo ""
echo "$SEP"
echo "=== 6. Recent Journal Errors ==="
echo "$SEP"
journalctl -u redis --since '1 hour ago' --no-pager -p err..emerg 2>/dev/null | tail -30 \
|| echo "[INFO] No recent journal errors for redis unit"
echo ""
echo "$SEP"
echo "=== 7. Config: Bind, Port, Auth, Limits ==="
echo "$SEP"
if [ -f "$REDIS_CONF" ]; then
grep -E '^(bind|protected-mode|port|maxclients|maxmemory[^-]|maxmemory-policy|requirepass|logfile|dir|save )' "$REDIS_CONF"
else
echo "[WARN] Config not found at $REDIS_CONF"
fi
echo ""
echo "$SEP"
echo "=== 8. Directory Permissions ==="
echo "$SEP"
for dir in /var/run/redis /var/log/redis "$REDIS_DATA"; do
if [ -e "$dir" ]; then
echo "--- $dir ---"
ls -la "$dir" | head -6
else
echo "[WARN] Directory $dir does not exist"
fi
done
echo ""
echo "$SEP"
echo "=== 9. Redis INFO (if reachable) ==="
echo "$SEP"
if redis-cli -p "$REDIS_PORT" PING 2>/dev/null | grep -q PONG; then
echo "--- Clients ---"
redis-cli -p "$REDIS_PORT" INFO clients
echo ""
echo "--- Memory ---"
redis-cli -p "$REDIS_PORT" INFO memory \
| grep -E 'used_memory_human|maxmemory_human|mem_fragmentation_ratio|rss'
echo ""
echo "--- Rejection + Command Stats ---"
redis-cli -p "$REDIS_PORT" INFO stats \
| grep -E 'rejected_connections|total_commands_processed|total_connections_received'
echo ""
echo "--- Persistence ---"
redis-cli -p "$REDIS_PORT" INFO persistence \
| grep -E 'rdb_|aof_enabled|aof_last'
echo ""
echo "--- Slowlog (top 10) ---"
redis-cli -p "$REDIS_PORT" SLOWLOG GET 10
else
echo "[WARN] Cannot reach Redis on port $REDIS_PORT — review steps 2-8 above"
fi
echo ""
echo "$SEP"
echo "=== 10. Kernel Tuning (overcommit + THP) ==="
echo "$SEP"
OC=$(cat /proc/sys/vm/overcommit_memory 2>/dev/null)
THP=$(cat /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null)
echo "vm.overcommit_memory = ${OC:-unknown} (Redis recommends: 1)"
echo "THP setting = ${THP:-unknown} (Redis recommends: never)"
[ "$OC" != "1" ] && echo "[ACTION] Run: echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf && sysctl -p"
echo "$THP" | grep -qv '\[never\]' && echo "[ACTION] Run: echo never > /sys/kernel/mm/transparent_hugepage/enabled"
echo ""
echo "$SEP"
echo "=== 11. Disk Space (RDB/AOF location) ==="
echo "$SEP"
df -h "$REDIS_DATA" 2>/dev/null || df -h /
echo ""
echo "$SEP"
echo "=== 12. Persistence File Integrity ==="
echo "$SEP"
RDB_FILE=$(grep '^dbfilename' "$REDIS_CONF" 2>/dev/null | awk '{print $2}' | tr -d '"')
RDB_DIR=$(grep '^dir' "$REDIS_CONF" 2>/dev/null | awk '{print $2}' | tr -d '"')
RDB_PATH="${RDB_DIR:-/var/lib/redis}/${RDB_FILE:-dump.rdb}"
AOF_PATH="${RDB_DIR:-/var/lib/redis}/appendonly.aof"
[ -f "$RDB_PATH" ] && echo "RDB: $RDB_PATH ($(stat -c %s "$RDB_PATH") bytes, modified $(stat -c %y "$RDB_PATH"))" || echo "[INFO] RDB file not found at $RDB_PATH"
[ -f "$AOF_PATH" ] && echo "AOF: $AOF_PATH ($(stat -c %s "$AOF_PATH") bytes, modified $(stat -c %y "$AOF_PATH"))" || echo "[INFO] AOF file not found at $AOF_PATH"
echo ""
echo "$SEP"
echo "=== Diagnostic Complete ==="
echo "$SEP"Error Medic Editorial
Error Medic Editorial is a team of senior DevOps engineers and SREs with combined experience managing Redis clusters in high-traffic production environments across AWS, GCP, and bare-metal Linux. We specialize in incident post-mortems, performance tuning, and writing command-first troubleshooting guides that skip the theory and go straight to actionable fixes.