# Redis Max Clients Reached
Error Message
ERR max number of clients reachedOr:
Redis::ConnectionError: max number of clients reachedOr:
Could not connect to Redis: max number of clients reachedRoot Causes
- 1.maxclients limit too low - Default or configured limit insufficient
- 2.Connection leaks - Clients not closing connections properly
- 3.Connection pooling issues - Pool creating too many connections
- 4.Idle connections not closing - Connections staying open unnecessarily
- 5.High traffic spikes - Temporary surge exceeding capacity
- 6.Multiple application instances - Too many clients from many sources
Diagnosis Steps
Step 1: Check Current Client Count
```bash # Check connected clients redis-cli CLIENT LIST | wc -l
# Or use INFO redis-cli INFO clients
# Key fields: # connected_clients: current count # client_recent_max_input_buffer: buffer sizes # blocked_clients: clients waiting on blocking commands ```
Step 2: Check Max Clients Configuration
```bash # Check maxclients setting redis-cli CONFIG GET maxclients
# Default is typically 10000 ```
Step 3: Identify Client Sources
```bash # List all clients with details redis-cli CLIENT LIST
# Output fields: # id=<id> addr=<ip:port> fd=<file descriptor> name=<client_name> age=<seconds_connected> idle=<seconds_idle> ...
# Count by source IP redis-cli CLIENT LIST | awk '{print $2}' | cut -d= -f2 | cut -d: -f1 | sort | uniq -c | sort -rn ```
Step 4: Find Idle Connections
```bash # Find clients idle for more than 60 seconds redis-cli CLIENT LIST | awk -F'[ =]' '{for(i=1;i<=NF;i++) if($i=="idle") print $(i+1)}' | awk '$1 > 60 {print}'
# Or more detailed redis-cli CLIENT LIST | while read line; do idle=$(echo "$line" | grep -oP 'idle=\K[0-9]+') addr=$(echo "$line" | grep -oP 'addr=\K[^ ]+') if [ "$idle" -gt 60 ]; then echo "Idle client: $addr (idle: $idle seconds)" fi done ```
Step 5: Check for Name/Tagged Clients
```bash # Find clients with names (helpful for debugging) redis-cli CLIENT LIST | grep "name="
# Client names help identify source application ```
Solutions
Solution 1: Increase maxclients
```bash # Increase limit dynamically redis-cli CONFIG SET maxclients 20000
# Or in redis.conf # /etc/redis/redis.conf maxclients 20000 ```
Note: Each connection uses memory (approximately 8KB + buffers). Ensure you have enough memory.
Solution 2: Kill Idle Connections
```bash # Find and kill idle clients redis-cli CLIENT LIST | while read line; do idle=$(echo "$line" | grep -oP 'idle=\K[0-9]+') id=$(echo "$line" | grep -oP 'id=\K[0-9]+') if [ "$idle" -gt 300 ]; then # 5 minutes idle redis-cli CLIENT KILL ID $id fi done
# Or kill all idle clients over threshold redis-cli CLIENT KILL TYPE normal ```
Solution 3: Configure Timeout for Idle Clients
```bash # Set timeout (seconds) for idle connections redis-cli CONFIG SET timeout 300 # 5 minutes
# In redis.conf timeout 300
# Note: 0 means no timeout (default) ```
Solution 4: Fix Application Connection Handling
Node.js with ioredis:
```javascript const Redis = require('ioredis');
// Use connection pool correctly const redis = new Redis({ host: 'localhost', port: 6379, maxRetriesPerRequest: 3, enableReadyCheck: true, // Connection is reused automatically });
// Set client name for debugging redis.client('SETNAME', 'my-app-worker-1');
// Gracefully close on shutdown process.on('SIGTERM', async () => { await redis.quit(); process.exit(0); }); ```
Python with redis-py:
```python import redis from redis.connection import ConnectionPool
# Use connection pool pool = ConnectionPool( host='localhost', port=6379, max_connections=10 # Limit connections in pool )
r = redis.Redis(connection_pool=pool)
# Set client name r.client_setname('my-app-service')
# Close properly def cleanup(): pool.disconnect() ```
PHP with Predis:
```php <?php require 'vendor/autoload.php';
// Use connection pool $client = new Predis\Client([ 'scheme' => 'tcp', 'host' => '127.0.0.1', 'port' => 6379, ], [ 'connections' => Predis\Connection\PhpiredisSocketFactory::class ]);
// Set client name $client->client('SETNAME', 'my-php-app');
// Disconnect properly $client->disconnect(); ```
Solution 5: Implement Connection Pooling
```javascript // Node.js - create shared pool const { createPool } = require('generic-pool');
const redisPool = createPool({ create: async () => { const redis = new Redis({ host: 'localhost', port: 6379 }); await redis.client('SETNAME', 'pool-client'); return redis; }, destroy: async (redis) => { await redis.quit(); } }, { max: 10, // Maximum connections min: 2, // Minimum connections idleTimeoutMillis: 30000, acquireTimeoutMillis: 5000 });
// Use pool async function getFromCache(key) { const redis = await redisPool.acquire(); try { return await redis.get(key); } finally { await redisPool.release(redis); } } ```
Solution 6: Configure TCP Settings
```bash # Check current TCP settings sysctl net.core.somaxconn sysctl net.ipv4.tcp_max_syn_backlog
# Increase backlog sudo sysctl -w net.core.somaxconn=65535 sudo sysctl -w net.ipv4.tcp_max_syn_backlog=65535
# In redis.conf tcp-backlog 511 # Should be <= somaxconn ```
Solution 7: Monitor Client Connections
```bash #!/bin/bash # monitor_clients.sh
MAX_THRESHOLD=80
CURRENT=$(redis-cli INFO clients | grep connected_clients | cut -d: -f2 | tr -d '\r') MAX=$(redis-cli CONFIG GET maxclients | tail -1)
PERCENT=$((CURRENT * 100 / MAX))
if [ $PERCENT -gt $MAX_THRESHOLD ]; then echo "WARNING: Client connections at ${PERCENT}% (${CURRENT}/${MAX})" echo "Top client sources:" redis-cli CLIENT LIST | awk '{print $2}' | cut -d= -f2 | cut -d: -f1 | sort | uniq -c | sort -rn | head -5 exit 1 fi
echo "OK: Client connections at ${PERCENT}% (${CURRENT}/${MAX})" ```
Solution 8: Use Redis Sentinel for Scaling
For high connection requirements, use multiple Redis instances:
```bash # Set up Redis Sentinel for read scaling # Multiple replicas can handle read connections
# Master handles writes # Replicas handle reads # Distribute connections across replicas ```
Configuration for Production
```ini # /etc/redis/redis.conf
# Connection limits maxclients 10000
# Timeout for idle connections timeout 300
# TCP backlog tcp-backlog 511
# TCP keepalive tcp-keepalive 300
# Protected mode (use authentication) protected-mode yes requirepass your_secure_password ```
Application Best Practices
1. Always Set Client Names
// Set name after connection
redis.client('SETNAME', `app-${process.env.HOSTNAME}-${process.pid}`);2. Use Single Connection Per Process
```javascript // Don't create multiple Redis instances // Use singleton pattern
let redisInstance = null;
function getRedis() { if (!redisInstance) { redisInstance = new Redis({ host: 'localhost', port: 6379 }); } return redisInstance; } ```
3. Handle Shutdown Properly
```javascript // Always close connections on shutdown async function shutdown() { if (redisInstance) { await redisInstance.quit(); } }
process.on('SIGTERM', shutdown); process.on('SIGINT', shutdown); ```
4. Use Connection Pooling for Multi-process Apps
```python # For web servers with many workers # Use shared connection pool with limits
pool = ConnectionPool( host='redis-host', port=6379, max_connections=20 # Per worker pool ) ```
Monitoring Script
```bash #!/bin/bash # client_monitor.sh
while true; do CURRENT=$(redis-cli INFO clients | grep connected_clients | cut -d: -f2 | tr -d '\r') MAX=$(redis-cli CONFIG GET maxclients | tail -1) IDLE=$(redis-cli CLIENT LIST | awk -F'[ =]' '{for(i=1;i<=NF;i++) if($i=="idle") print $(i+1)}' | awk '$1 > 60' | wc -l)
echo "$(date): Connected: $CURRENT/$MAX, Idle (>60s): $IDLE"
if [ "$CURRENT" -gt 80 ]; then # Alert if approaching limit echo "HIGH CONNECTION COUNT" fi
sleep 10 done ```
Prevention Checklist
- [ ] Set appropriate maxclients limit
- [ ] Implement connection pooling
- [ ] Set timeout for idle connections
- [ ] Always close connections on shutdown
- [ ] Set client names for identification
- [ ] Monitor connection count
- [ ] Use single connection per process where possible
- [ ] Distribute read load across replicas
Related Errors
- [Redis Connection Refused](./fix-redis-connection-refused)
- [Redis Out of Memory](./fix-redis-out-of-memory)