Error Medic

Redis 'Connection Refused': Complete Troubleshooting Guide for Crashes, OOM, High CPU, and Service Failures

Fix Redis 'Connection refused', OOM kills, high CPU, too many connections, and permission denied with step-by-step diagnostic commands and proven solutions.

Last updated:
Last verified:
2,742 words
Key Takeaways
  • Connection refused means Redis is not running, crashed due to an OOM kill, or is bound only to 127.0.0.1 when connecting remotely — always start with 'systemctl status redis' and 'ss -tlnp | grep 6379'
  • Redis OOM comes in two forms: the Linux kernel OOM killer silently terminates the process (check 'dmesg | grep oom') or Redis hits its internal maxmemory limit and clients receive '(error) OOM command not allowed'
  • High CPU is almost always caused by O(N) commands like KEYS or SMEMBERS on large sets — enable the slow log with 'redis-cli config set slowlog-log-slower-than 10000' and review with 'redis-cli slowlog get 25'
  • Too many connections exhausts maxclients (default 10000); fix connection leaks first, then add 'tcp-keepalive 300' to redis.conf and raise maxclients if needed
  • Quick triage sequence: systemctl status redis → journalctl -u redis --since '1 hour ago' → redis-cli ping → redis-cli info all — this covers 90% of failure modes
Redis Fix Approaches Compared
MethodWhen to UseTimeRisk
systemctl restart redisService crashed, AOF/RDB intact, data safe to reload< 1 minLow — safe if persistence is enabled
redis-cli config set maxmemory-policy allkeys-lruClients receiving OOM error, maxmemory limit hit, need immediate unblockInstantLow — may evict keys; verify TTL strategy first
Raise maxclients + tcp-keepalive 300ERR max number of clients reached errors in application logs2–5 min (requires restart)Low — test in staging, check ulimit -n first
Disable appendfsync always → everysecHigh CPU or I/O latency caused by AOF fsync on every writeInstant via CONFIG SETMedium — reduces durability from every-write to per-second
Rebind to private IP + requirepassConnection refused from remote hosts due to bind 127.0.0.15–10 minHigh — exposes Redis to network; add firewall rules first
sysctl -w vm.overcommit_memory=1BGSAVE fails with 'fork: Cannot allocate memory'< 1 minLow — standard Redis production requirement

Understanding Redis 'Connection Refused' and Related Failures

The ECONNREFUSED error appears in application logs as:

Error: Redis connection to 127.0.0.1:6379 failed - connect ECONNREFUSED 127.0.0.1:6379

Or directly in redis-cli as:

Could not connect to Redis at 127.0.0.1:6379: Connection refused

This is always a symptom, never a root cause. The process may have crashed, been killed by the Linux OOM killer, failed to start due to a permission error, or be listening on the wrong interface. Each scenario requires a different fix.

Step 1: Verify Whether Redis Is Running

Start with the most basic check — is the process alive?

systemctl status redis           # Debian/Ubuntu service name
systemctl status redis-server    # Alternative service name (RHEL/CentOS)
pgrep -x redis-server            # Returns PID if running, nothing if not
ss -tlnp | grep 6379             # Verify the process is actually listening

If systemctl status shows Active: failed (Result: exit-code) or Active: inactive (dead), the service is not running. Proceed to Step 2. If the process is running but connections are still refused, skip to Step 8 (bind address and firewall).

Step 2: Read the Startup Failure in the Journal

journalctl -u redis --since "2 hours ago" --no-pager | tail -50

Common startup error messages and their fixes:

Permission denied on data files:

FATAL: Can't open/create append only file. Permission denied.

Fix the ownership of the Redis data directory:

ls -la /var/lib/redis/
chown -R redis:redis /var/lib/redis/
chmod 750 /var/lib/redis/

Port already in use:

Creating Server TCP listening socket 127.0.0.1:6379: bind: Address already in use

Find the conflicting process and kill it:

lsof -i :6379
kill -9 <PID>

Background save fork failure:

Can't save in background: fork: Cannot allocate memory

Redis requires vm.overcommit_memory = 1 to safely fork for RDB snapshots. Without it, the kernel refuses the fork even when memory is technically available under copy-on-write semantics:

sysctl vm.overcommit_memory           # Should return 1
sysctl -w vm.overcommit_memory=1
echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf

Step 3: Read the Redis Crash Log

When Redis crashes (SIGSEGV, assertion failure, or watchdog timeout), it writes a crash report to its configured log file. Find the path:

grep 'logfile' /etc/redis/redis.conf
# Typical paths:
# /var/log/redis/redis-server.log  (Debian/Ubuntu)
# /var/log/redis/redis.log         (RHEL/CentOS)
tail -200 /var/log/redis/redis-server.log | grep -A 80 'REDIS BUG REPORT'

The crash report begins with === REDIS BUG REPORT START: Cut & paste starting from here === and contains the Redis version, OS details, available memory at crash time, and a full stack trace. This is the primary artifact for filing a GitHub issue.

If Redis was killed by the Linux OOM killer, it will NOT appear in the Redis log. Check kernel ring buffer and syslog:

dmesg | grep -i 'oom' | tail -20
dmesg | grep -i 'killed process' | tail -10
grep -i 'redis' /var/log/syslog | grep -i 'kill' | tail -10

Output containing redis-server invoked oom-killer or Killed process <PID> (redis-server) confirms an OOM kill. Proceed to Step 4.

Step 4: Fix Redis OOM (Out of Memory) Errors

Redis OOM problems manifest in two completely different ways that require different fixes:

Form 1 — Linux OOM killer terminates Redis (process disappears, nothing in Redis log):

  • Root cause: System physical memory exhausted; kernel scored Redis as the best kill candidate
  • Fix: Set maxmemory in redis.conf to cap Redis memory usage below total RAM (leave 15–20% for the OS and other processes), then restart
  • Also set an eviction policy so Redis gracefully removes old data instead of growing unbounded

Form 2 — Redis internal OOM, clients receive an error string:

(error) OOM command not allowed when used memory > 'maxmemory'.
  • Root cause: Redis hit its configured maxmemory limit with maxmemory-policy noeviction
  • Fix:
# Inspect current memory state:
redis-cli info memory | grep -E 'used_memory_human|maxmemory_human|maxmemory_policy'

# Raise the limit at runtime (takes effect immediately, not persisted across restart):
redis-cli config set maxmemory 4gb

# Enable LRU eviction so Redis auto-manages memory:
redis-cli config set maxmemory-policy allkeys-lru

# Persist both changes to redis.conf:
redis-cli config rewrite

Common eviction policy choices: allkeys-lru (evict any key by LRU, recommended for caches), volatile-lru (evict only keys with TTL set), allkeys-lfu (Redis 4.0+, evict by access frequency).

Step 5: Fix 'ERR max number of clients reached'

When Redis exhausts its connection limit (default 10,000), new clients receive:

(error) ERR max number of clients reached

Diagnose the connection state before blindly raising the limit:

# Current client counts:
redis-cli info clients
# connected_clients: active connections
# blocked_clients: waiting on BLPOP/BRPOP
# tracking_clients: CLIENT TRACKING subscribers

# Find long-idle connections (connection leak indicator):
# Any client idle for >3600 seconds is almost certainly a leaked connection:
redis-cli client list | grep -o 'idle=[0-9]*' | sort -t= -k2 -rn | head -20

Fixes in order of priority:

  1. Fix the connection leak — idle clients sitting for thousands of seconds indicate the application is not returning connections to the pool. Audit your Redis client library pool configuration (max_connections, timeout, min_idle).
  2. Enable TCP keepalive to reclaim half-open connections: add tcp-keepalive 300 to redis.conf
  3. Raise maxclients: redis-cli config set maxclients 20000 — also requires increasing the OS file descriptor limit:
ulimit -n   # Check current limit; must be > maxclients
echo 'redis soft nofile 65535' >> /etc/security/limits.conf
echo 'redis hard nofile 65535' >> /etc/security/limits.conf
  1. Fix TCP backlog warning (often logged at startup alongside connection errors):
WARNING: The TCP backlog setting of 511 cannot be enforced because
/proc/sys/net/core/somaxconn is set to the lower value of 128.

Fix: sysctl -w net.core.somaxconn=511

Step 6: Diagnose and Fix Redis High CPU

Redis is single-threaded for command processing (Redis 6+ uses I/O threads but command execution remains serial). Sustained CPU above 80% has four common root causes:

A. Expensive O(N) commands

KEYS *, SMEMBERS on million-member sets, LRANGE list 0 -1, HGETALL on large hashes, and SORT without LIMIT are the most common offenders. Enable the slow log to catch them:

redis-cli config set slowlog-log-slower-than 10000   # Flag commands taking >10ms
redis-cli config set slowlog-max-len 128
redis-cli slowlog get 25
# Each entry: [id, unix_timestamp, duration_microseconds, [command args...]]

Replace KEYS * with cursor-based SCAN 0 COUNT 100 iteration. Replace SMEMBERS on large sets with SSCAN.

B. High command throughput

redis-cli --stat                                          # Live ops/sec, memory, clients
redis-cli info stats | grep instantaneous_ops_per_sec

C. Fork latency during BGSAVE or BGREWRITEAOF

redis-cli info persistence | grep -E 'rdb_last_bgsave_time_sec|aof_last_rewrite_time_sec'

If background save takes >5 seconds on a 2 GB dataset, the server lacks enough RAM for copy-on-write pages. Reduce dataset size, add memory, or tune save intervals.

D. AOF fsync on every write

redis-cli config get appendfsync
# 'always' flushes to disk on every write — extremely CPU- and I/O-intensive
redis-cli config set appendfsync everysec    # Flush once per second instead

Step 7: Fix Redis Slow Performance

Beyond CPU, Redis latency can spike from swap usage, OS interference, or large values:

Check for swap usage (catastrophic for Redis performance — a single page fault can add milliseconds of latency):

cat /proc/$(pgrep redis-server)/status | grep VmSwap
# Any non-zero VmSwap means Redis is paging to disk
redis-cli info memory | grep -E 'used_memory_human|maxmemory_human'

Measure baseline latency:

redis-cli --latency -h 127.0.0.1 -p 6379
redis-cli --latency-history -h 127.0.0.1 -p 6379 -i 5
# Latency >1ms on localhost indicates OS-level interference

Disable Transparent Huge Pages — Redis warns about this at startup and it is a documented source of multi-millisecond latency spikes:

WARNING you have Transparent Huge Pages (THP) support enabled in your kernel.
This will create latency and memory usage issues with Redis.

Fix:

echo never > /sys/kernel/mm/transparent_hugepage/enabled
# Persist across reboots:
echo 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' >> /etc/rc.local

Find large keys causing serialization overhead:

redis-cli --bigkeys     # Largest key per data type
redis-cli --memkeys     # Memory usage per key (Redis 4.0+)

Keys with values >100 KB cause network and serialization latency. Compress values at the application layer or split large hashes and sets.

Step 8: Fix Bind Address and Firewall Issues

If Redis is running but remote connections are refused, the bind address is almost always the cause:

grep '^bind' /etc/redis/redis.conf
# Default in Redis 3.2+: bind 127.0.0.1 -::1
# This explicitly restricts connections to loopback only.
# Remote clients will receive: Connection refused

To allow connections from a specific private network interface (preferred over 0.0.0.0):

# Edit redis.conf:
# bind 127.0.0.1 10.0.1.5

# Always require authentication when exposing to any network:
redis-cli config set requirepass 'yourStrongPassphrase99!'
redis-cli config rewrite

Verify firewall rules permit port 6379:

iptables -L -n | grep 6379
ufw status verbose | grep 6379
# Allow a specific subnet:
ufw allow from 10.0.1.0/24 to any port 6379

Check protected-mode — when Redis is bound to a non-loopback address without a password, protected mode blocks all external connections and logs:

Protected mode is enabled and no password is set.
Aborting for security. Listening on 0.0.0.0 with protected-mode on and no auth.

Fix: Set requirepass (recommended) or explicitly set protected-mode no only on isolated private networks with firewall enforcement.

Frequently Asked Questions

bash
#!/usr/bin/env bash
# Redis Comprehensive Diagnostic Script
# Run as root or redis user on the Redis host

set -euo pipefail

echo '=== Redis Service Status ==='
systemctl status redis redis-server 2>/dev/null | head -20 || true
pgrep -x redis-server && echo 'Process: RUNNING' || echo 'Process: NOT FOUND'

echo ''
echo '=== Port Listening Check ==='
ss -tlnp | grep 6379 || echo 'WARN: Nothing listening on port 6379'

echo ''
echo '=== Recent Journal Errors (last 2 hours) ==='
journalctl -u redis -u redis-server --since '2 hours ago' --no-pager -p err 2>/dev/null | tail -30 || true

echo ''
echo '=== Redis Ping Test ==='
redis-cli ping 2>/dev/null || echo 'FAIL: Cannot connect to Redis on 127.0.0.1:6379'

echo ''
echo '=== Redis Info Summary ==='
redis-cli info all 2>/dev/null | grep -E '^(redis_version|uptime_in_seconds|connected_clients|blocked_clients|used_memory_human|maxmemory_human|maxmemory_policy|used_memory_peak_human|mem_fragmentation_ratio|rdb_last_bgsave_status|aof_enabled|aof_last_write_status|total_commands_processed|instantaneous_ops_per_sec|total_connections_received|rejected_connections|latest_fork_usec):' || true

echo ''
echo '=== OOM Kernel Events ==='
dmesg | grep -i 'oom' | tail -10 || echo 'No OOM events found in dmesg'
dmesg | grep -i 'killed process' | tail -5 || true

echo ''
echo '=== Slow Log (last 10 entries) ==='
redis-cli config set slowlog-log-slower-than 10000 2>/dev/null || true
redis-cli slowlog get 10 2>/dev/null || echo 'Could not read slow log'

echo ''
echo '=== Connection Leak Detection (top idle clients) ==='
redis-cli client list 2>/dev/null | grep -o 'idle=[0-9]*' | sort -t= -k2 -rn | head -20 || true

echo ''
echo '=== Large Keys Scan ==='
redis-cli --bigkeys 2>/dev/null | tail -30 || echo 'Could not scan keys'

echo ''
echo '=== Swap Usage Check ==='
PID=$(pgrep -x redis-server 2>/dev/null || echo '')
if [ -n "$PID" ]; then
  grep VmSwap /proc/$PID/status
else
  echo 'Redis not running, cannot check swap'
fi

echo ''
echo '=== Key System Settings ==='
echo "vm.overcommit_memory = $(sysctl -n vm.overcommit_memory)"
echo "net.core.somaxconn   = $(sysctl -n net.core.somaxconn)"
echo "THP enabled          = $(cat /sys/kernel/mm/transparent_hugepage/enabled)"

echo ''
echo '=== Redis Config Highlights ==='
CONF=$(redis-cli config get '*' 2>/dev/null | paste - - | grep -E '^(bind|protected-mode|requirepass|maxmemory |maxclients|tcp-keepalive|appendfsync|save|logfile|dir) ' || true)
echo "${CONF:-Could not retrieve config via CONFIG GET — check requirepass}"

echo ''
echo '=== Firewall Rules for Port 6379 ==='
iptables -L -n 2>/dev/null | grep 6379 || echo 'No iptables rules for 6379 (or not root)'
ufw status 2>/dev/null | grep 6379 || true

echo ''
echo '=== Disk Space on Redis Data Dir ==='
DATA_DIR=$(redis-cli config get dir 2>/dev/null | tail -1 || echo '/var/lib/redis')
df -h "$DATA_DIR" | tail -1

echo ''
echo '=== Diagnostic Complete ==='
E

Error Medic Editorial

Error Medic Editorial is a team of senior DevOps engineers and SREs with 10+ years of production experience running Redis at scale on Linux. We specialize in infrastructure reliability, performance tuning, and writing precise, command-driven troubleshooting guides for engineers who need answers fast.

Sources

Related Articles in Redis

Explore More Linux Sysadmin Guides