Error Medic

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.

Last updated:
Last verified:
2,864 words
Key Takeaways
  • 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
Fix Approaches Compared
MethodWhen to UseTimeRisk
systemctl restart redisService crashed or stopped; no hardware issue< 1 minLow — data loss only if persistence disabled
Fix bind/protected-mode in redis.confRemote clients refused; localhost connects fine5 minLow — test with redis-cli -h <ip> before reload
Raise maxclients (CONFIG SET maxclients)ECONNREFUSED under load; redis-server is running2 minLow — takes effect immediately without restart
chown -R redis:redis runtime dirsPermission denied on socket or PID file at startup2 minLow
Set maxmemory + vm.overcommit_memory=1OOM kills visible in dmesg; Redis terminated by kernel5 minMedium — tune maxmemory carefully to avoid eviction storms
redis-check-aof --fix / redis-check-rdbRedis exits immediately citing corrupt persistence file15–60 minMedium — may lose writes since last clean snapshot
Tune tcp-backlog and net.core.somaxconnConnection timeouts under burst traffic spikes5 minLow — 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 upgrade
  • Creating Server TCP listening socket 127.0.0.1:6379: bind: Address already in use — port held by a zombie redis-server or another process
  • Fatal 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:

  1. Fix connection pool configuration in your application — set a reasonable max_connections and ensure connections are returned to the pool after use
  2. Enable TCP keepalive: add tcp-keepalive 60 to redis.conf — this evicts connections that have gone away without a proper FIN
  3. Raise the ceiling temporarily: redis-cli CONFIG SET maxclients 25000
  4. 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 with SCAN 0 COUNT 100 iteratively
  • SMEMBERS on sets with millions of members — paginate with SSCAN
  • Unthrottled MONITOR left 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

bash
#!/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"
E

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.

Sources

Related Articles in Redis

Explore More Linux Sysadmin Guides