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.
- 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
| Method | When to Use | Time | Risk |
|---|---|---|---|
| systemctl restart redis | Service crashed, AOF/RDB intact, data safe to reload | < 1 min | Low — safe if persistence is enabled |
| redis-cli config set maxmemory-policy allkeys-lru | Clients receiving OOM error, maxmemory limit hit, need immediate unblock | Instant | Low — may evict keys; verify TTL strategy first |
| Raise maxclients + tcp-keepalive 300 | ERR max number of clients reached errors in application logs | 2–5 min (requires restart) | Low — test in staging, check ulimit -n first |
| Disable appendfsync always → everysec | High CPU or I/O latency caused by AOF fsync on every write | Instant via CONFIG SET | Medium — reduces durability from every-write to per-second |
| Rebind to private IP + requirepass | Connection refused from remote hosts due to bind 127.0.0.1 | 5–10 min | High — exposes Redis to network; add firewall rules first |
| sysctl -w vm.overcommit_memory=1 | BGSAVE fails with 'fork: Cannot allocate memory' | < 1 min | Low — 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
maxmemoryinredis.confto 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
maxmemorylimit withmaxmemory-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:
- 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). - Enable TCP keepalive to reclaim half-open connections: add
tcp-keepalive 300toredis.conf - 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
- 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
#!/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 ==='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.