ERR max number of clients reached
REDIS_CONNECTION_ERROR: connect ECONNREFUSED 127.0.0.1:6379
ReplyError: ERR max number of clients reached
# In application logs:
Error: Redis connection pool exhausted — timeout waiting for connection
RedisError: Connection pool timeout after 5000ms
Redis has a maxclients setting (default: 10,000) limiting simultaneous connections. When hit, all new connection attempts fail immediately. Unlike PostgreSQL, Redis connections are extremely lightweight — hitting this limit usually signals a connection leak.
# Connect to Redis and check info
redis-cli -h <host> -p <port> INFO clients
# Output you'll see:
connected_clients:9987 # Current connections
blocked_clients:0
tracking_clients:0
clients_in_timeout_table:0
maxclients:10000 # Your limit
# Check the limit
redis-cli CONFIG GET maxclients
# List all connected clients
redis-cli CLIENT LIST
# Output shows: addr, fd, name, age, idle time, cmd
# Look for: high idle time = connection leak
# addr=10.0.1.5:54321 ... idle=3847 ... cmd=NULL
# ^^ connected 3847 seconds idle = leaked connection
# Count connections per source IP
redis-cli CLIENT LIST | awk '{print $2}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -20
redis-cli INFO stats | grep -E "total_connections_received|rejected_connections"
# total_connections_received: running total since start
# rejected_connections: connections refused due to maxclients
# If rejected_connections > 0 — you're actively hitting the limit
The most common cause. Application code opens Redis connections but error paths (exceptions, timeouts, crashes) don't properly return them to the pool. Connections accumulate as idle/leaked.
# Bad pattern (connection leak)
async function getUser(id) {
const client = await pool.getConnection(); // gets connection
try {
return await client.get(`user:${id}`);
} catch (err) {
throw err; // connection never returned on error!
}
}
# Good pattern (connection always returned)
async function getUser(id) {
const client = await pool.getConnection();
try {
return await client.get(`user:${id}`);
} finally {
client.release(); // always release, even on error
}
}
Deploy scaled up pods from 5 → 20. Each pod has a connection pool of 50 = 1000 connections. Previously 5 × 50 = 250 connections (fine). Now 20 × 50 = 1000 (hitting limit).
# Check connection pool size per service
# In Node.js (ioredis):
const redis = new Redis.Cluster(nodes, {
scaleReads: 'slave',
maxRetriesPerRequest: 3,
connectionPoolSize: 10 # Lower this if scaling out
});
# In Python (redis-py):
pool = redis.ConnectionPool(
host='localhost',
port=6379,
max_connections=10 # Lower per-process pool size
)
Default is 10,000 — usually fine. But some managed Redis providers (ElastiCache small instances, Redis Cloud) set lower limits. Check your provider's actual limit.
# Increase maxclients (no restart needed)
redis-cli CONFIG SET maxclients 20000
# Make persistent in redis.conf
maxclients 20000
# AWS ElastiCache: modify via parameter group
# Redis Cloud: contact support or upgrade plan
Pub/sub subscriber connections are long-lived. If subscriber clients crash without unsubscribing, Redis keeps the connection open indefinitely.
# See subscription connections
redis-cli CLIENT LIST | grep "sub=" | awk '{print $2, $NF}'
# Kill stale subscription connections
redis-cli CLIENT KILL ID <client-id>
# Or kill all idle connections older than 300 seconds
redis-cli CLIENT NO-EVICT on
redis-cli CLIENT NO-TOUCH on
service: session-service
error: ERR max number of clients reached — cache reads failing
logs: connected_clients: 9987/10000
CLIENT LIST shows 8400 connections idle > 600s from app-server-pods
recent changes: deployed v2.1 — scaled from 8 to 32 pods
Root cause:
Connection leak compounded by pod scale-out. Each of 32 pods maintains 250 connections (vs 8 pods × 250 = 2000 before). 8400 idle connections indicate error paths not returning connections to pool.
# 1. Kill all idle connections immediately
redis-cli CLIENT KILL SKIPME yes IDLE 60
# 2. Or kill connections from specific IP (if one service is leaking)
redis-cli CLIENT KILL ADDR <app-server-ip>:0
# 3. Temporarily increase maxclients to buy time
redis-cli CONFIG SET maxclients 20000
# 4. Monitor connected_clients dropping
watch -n 2 "redis-cli INFO clients | grep connected_clients"
# 5. Once connections drop — identify the leaking service
redis-cli CLIENT LIST | awk '{print $2}' | cut -d: -f1 | \
sort | uniq -c | sort -rn | head -5
timeout 300 in redis.conf kills idle connections automatically