The 'LOADING Redis is loading the dataset in memory' error occurs when a client attempts to connect to a Redis server that is still initializing and loading persisted data from disk. This is a temporary state during startup or replica resynchronization that prevents commands from executing until the dataset is fully loaded.
The "LOADING Redis is loading the dataset in memory" error is a temporary state indicator, not a permanent failure. Redis returns this error when: 1. **Startup Recovery**: A Redis server is starting and loading a snapshot (RDB file) or append-only file (AOF) from disk into memory. This process takes time for large datasets. 2. **Replica Resynchronization**: A slave (replica) Redis server is performing a full resynchronization with the master, downloading the entire dataset to restore it locally. 3. **Hybrid Persistence**: Redis is loading both the RDB snapshot and replaying AOF changes on top of it (supported in Redis 4.0+). During this loading phase, Redis accepts TCP connections on its port but rejects all commands with the LOADING error. The error goes away automatically once loading completes. This is intentional behavior—Redis prioritizes data correctness over availability during startup. The key distinction is that this error is **expected and temporary**. It becomes problematic only if: - Loading takes unexpectedly long (indicating performance or data issues) - Application retry logic doesn't account for this transient state - Health checks don't wait for the LOADING phase to complete - The server appears stuck in LOADING state permanently
The LOADING error is normal and expected during Redis startup or replica resynchronization. It's not a crash or data corruption—it's Redis telling you it's not ready to serve requests yet.
Monitor the startup process:
# Watch Redis startup logs
redis-cli INFO server | grep loading
# Output: loading:0 means finished, loading:1 means still loading
# Check how much is loaded
redis-cli INFO server | grep loading_changes_per_secFor Docker containers:
# Check logs to see when loading completes
docker logs <container_name> | grep "Ready to accept"
# This message indicates loading is completeExpected timeline:
- Small dataset (< 1GB): Usually finishes in milliseconds
- Medium dataset (1-10GB): Typically completes in seconds
- Large dataset (> 10GB): May take 10-60+ seconds depending on disk speed
The most robust solution is to handle the LOADING error gracefully in your application by retrying with backoff:
Node.js with ioredis:
const Redis = require('ioredis');
const redis = new Redis({
host: 'localhost',
port: 6379,
maxRetriesPerRequest: null,
enableReadyCheck: false,
// Exponential backoff for retries
retryStrategy: (times) => {
const delay = Math.min(times * 50, 2000);
return delay;
},
// Handle LOADING error
lazyConnect: true,
});
redis.on('error', (err) => {
if (err.message.includes('LOADING')) {
console.log('Redis is loading, retrying...');
// ioredis automatically retries with backoff
}
});
// Connect with retry
await redis.connect();Node.js with redis:
const { createClient } = require('redis');
const client = createClient({
host: 'localhost',
port: 6379,
socket: {
reconnectStrategy: (retries) => {
if (retries > 10) return new Error('Max retries reached');
return Math.min(retries * 50, 500);
},
},
});
client.on('error', (err) => {
if (err.message.includes('LOADING')) {
console.log('Waiting for Redis to load...');
}
});
await client.connect();Python with redis-py:
import redis
import time
def get_redis_with_retry(host='localhost', port=6379, max_retries=30):
for attempt in range(max_retries):
try:
r = redis.Redis(host=host, port=port, decode_responses=True)
r.ping() # Test connection
return r
except redis.ConnectionError as e:
if 'LOADING' in str(e):
print(f"Redis loading, retrying in {2**attempt}ms...")
time.sleep(2**attempt / 1000)
else:
raise
raise Exception("Could not connect to Redis after retries")
redis_client = get_redis_with_retry()Go with go-redis:
package main
import (
"github.com/redis/go-redis/v9"
"time"
)
func main() {
opts := &redis.Options{
Addr: "localhost:6379",
}
// Add custom retry backoff
opts.Retry = func(ctx context.Context, attempt int, err error) time.Duration {
if strings.Contains(err.Error(), "LOADING") {
backoff := time.Duration(math.Pow(2, float64(attempt))) * 50 * time.Millisecond
return backoff
}
return 0
}
client := redis.NewClient(opts)
_ = client.Ping(ctx)
}Health checks often query the server before loading completes. Adjust timeouts and retry settings:
Docker health check:
FROM redis:latest
# Simple approach: wait before first health check
HEALTHCHECK --interval=5s --timeout=3s --start-period=10s --retries=3 \
CMD redis-cli ping || exit 1The --start-period=10s parameter is crucial—it gives Redis 10 seconds to load before health checks start counting failures.
Kubernetes liveness and readiness probes:
apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
- name: redis
image: redis:latest
ports:
- containerPort: 6379
# Readiness probe: waits before declaring "ready"
readinessProbe:
exec:
command:
- redis-cli
- ping
initialDelaySeconds: 15 # Wait 15 seconds before first check
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
# Liveness probe: restarts if stuck in LOADING
livenessProbe:
exec:
command:
- redis-cli
- ping
initialDelaySeconds: 30 # Wait 30 seconds before checking
periodSeconds: 10
failureThreshold: 3Docker Compose:
version: '3.8'
services:
redis:
image: redis:latest
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 3
start_period: 10s # Critical: wait 10s before health checksIf Redis takes too long to load, the issue might be the persistence files, not the database itself. Monitor and optimize:
Check file sizes:
# Check RDB snapshot size
ls -lh /var/lib/redis/dump.rdb
# Check AOF size (can grow very large)
ls -lh /var/lib/redis/appendonly.aof
# Expected load times (rough estimates):
# 1GB: ~1-2 seconds (depends on disk speed)
# 10GB: ~10-20 seconds
# 100GB: ~100+ secondsOptimize persistence for faster loading:
# 1. Use RDB-only mode for faster startup (trades durability for speed)
# In redis.conf:
appendonly no
save 900 1 # Snapshot every 15 minutes with 1+ changes
# 2. Enable Redis Hybrid Persistence (Redis 4.0+) - combines RDB + AOF for fastest recovery
# in redis.conf:
aof-use-rdb-preamble yes
# 3. For very large datasets, consider switching to faster storage
# Mount Redis data on NVMe or SSD instead of HDDMonitor during startup:
# In another terminal, watch the loading progress
watch -n 1 "redis-cli INFO server | grep loading"
# Check system I/O during loading
iostat -x 1 # Linux
# or
ioutil # macOSIf LOADING takes unusually long (hours), the persistence file may be corrupted. Check and repair:
For RDB files:
# Check RDB file integrity
redis-check-rdb /var/lib/redis/dump.rdb
# If corrupted, delete it (data will be lost)
# But Redis will start immediately
redis-cli SHUTDOWN
rm /var/lib/redis/dump.rdb
systemctl start redis
# To prevent data loss, ensure replicas are running
# Copy RDB from a healthy replica instead of deletingFor AOF files:
# AOF files can become corrupted at the end (disk full, crash, etc.)
# Check and auto-repair
redis-check-aof --fix /var/lib/redis/appendonly.aof
# This will truncate corrupted entries and write a backup:
# /var/lib/redis/appendonly.aof.bak
# Then restart Redis
systemctl restart redisFor hybrid persistence (RDB + AOF):
# If both files exist, AOF takes precedence
# Check if AOF is causing the slowness
redis-cli CONFIG GET appendonly
# If yes, temporarily disable it for faster startup
redis-cli CONFIG SET appendonly no
# Then BGSAVE to create a fresh RDB snapshot
redis-cli BGSAVEPrevent future corruption:
# Enable AOF rewrite to keep AOF file smaller and corruption-resistant
redis-cli CONFIG SET auto-aof-rewrite-percentage 100
redis-cli CONFIG SET auto-aof-rewrite-min-size 67108864 # 64MB
# Enable RDB checksums (Redis 5.0+)
redis-cli CONFIG SET rdb-save-incremental-fsync yesIf the LOADING error occurs during replica failover or master change, the replica needs to sync the full dataset:
Monitor replica sync progress:
# Connect to the replica and check its status
redis-cli -p 6380 INFO replication
# Look for these fields:
# - role: slave
# - master_link_status: up/down
# - slave_read_only: yes
# - repl_backlog_active: 1 (syncing)Prevent long resynchronization waits:
# In redis.conf, tune replication settings:
# Increase repl-diskless-sync for large datasets
repl-diskless-sync yes
repl-diskless-sync-delay 5
# Increase backlog to prevent full syncs on minor disconnects
repl-backlog-size 512mb # Default 1MB is too small
repl-backlog-ttl 3600 # Keep backlog for 1 hour
# Increase timeout to avoid unnecessary resync attempts
repl-timeout 60
# After changing, restart replica
systemctl restart redis-replicaFor multi-tier replication (slave-of-slave):
# If you have cascading replicas, partial resync is even more critical
# Configure each replica to keep a large backlog
# Monitor replication chain
redis-cli INFO replication # On each instanceIf LOADING delays are unacceptable for your use case, consider:
For cache-only usage (no persistence needed):
# Disable persistence entirely for instant startup
# In redis.conf:
save "" # Disable RDB snapshots
appendonly no # Disable AOF
# This trades durability for availability
# Suitable for session stores, real-time caching, leaderboards
systemctl restart redis
# Redis will start immediately and be ready to serveFor critical applications, use Redis Cluster or Sentinel:
# Redis Sentinel automatically fails over to a healthy replica
# Replicas are promoted instantly without re-syncing the entire dataset
# Configuration in sentinel.conf:
sentinel monitor mymaster 127.0.0.1 6379 1
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 10000
# Start Sentinel
redis-sentinel /etc/redis/sentinel.confFor zero-downtime deployments:
# Use Redis Cluster with multiple masters
# Shards remain available even if one node is loading
# Example with 3 masters + 3 replicas:
redis-cluster create \
127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 \
127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
# One node loading doesn't affect the other 5Alternative: Use external memory stores during LOADING:
// Implement fallback logic
async function getFromRedisWithFallback(key) {
try {
const val = await redis.get(key);
return val;
} catch (err) {
if (err.message.includes('LOADING')) {
// Fall back to database during Redis loading
return await database.get(key);
}
throw err;
}
}After applying fixes, confirm Redis is fully loaded and ready:
# Test basic command execution
redis-cli ping
# Should respond with PONG, not LOADING
# Check INFO server output
redis-cli INFO server | grep loading
# Should show: loading:0
# For replication, verify sync completed
redis-cli INFO replication
# Master: should show connected_slaves > 0
# Replica: should show master_link_status:up
# For large datasets, verify all keys loaded
redis-cli DBSIZE
# Should return the expected number of keys
# Test application connection
# Your application should be able to execute commands normallyMonitor ongoing performance:
# Watch memory usage during loading
redis-cli INFO memory | grep used_memory_human
# Check instantaneous operations per second
redis-cli INFO stats | grep instantaneous_ops_per_sec
# Once loading is complete, this should increase dramatically
# showing Redis is now actively serving requestsWhy Redis Opens Port Before Loading Data
This is a known architectural choice in Redis. The server opens its TCP port immediately to enable out-of-band health checks and diagnostic commands, but blocks data operations until loading completes. Some argue this design is suboptimal—that the port should only open after loading finishes. However, this would prevent administrators from monitoring the loading progress itself.
RDB vs AOF Loading Performance
- RDB (snapshot): Direct binary deserialization, very fast. Load speed is limited by disk I/O and CPU (typically 1-2GB/second on modern hardware).
- AOF (append-only): Must re-execute every command sequentially, much slower. A large AOF file with millions of commands takes minutes to replay.
- Hybrid mode (Redis 4.0+): RDB preamble in AOF file. Fast RDB loading + incremental AOF replay = best of both worlds.
For datasets > 10GB, RDB+Hybrid is strongly recommended.
Replica Synchronization Details
There are two sync modes:
1. Full resync: Replica receives entire dataset from master (SYNC command). Slower but recovers from large deltas.
2. Partial resync: Replica only gets missed commands from the replication backlog. Must keep backlog large enough for network hiccups.
Configure repl-backlog-size generously (512MB+) to avoid unnecessary full syncs.
Persistence Trade-offs
| Mode | Speed | Durability | Failure Recovery | Use Case |
|------|-------|-----------|-----------------|----------|
| None (cache) | ✓✓✓ | ✗ | Instant | Session cache, real-time data |
| RDB only | ✓✓ | ✓ (snapshots) | Loading takes time | Session store, leaderboards |
| AOF only | ✓ | ✓✓✓ (every write) | Very slow replay | Critical data, strong durability needs |
| RDB + AOF | ✓✓ | ✓✓✓ | Fast (hybrid) | Production data stores |
Monitoring Tools
- redis-cli INFO: Built-in, shows all metrics including loading:0/1
- redis-cli MONITOR: Stream all commands (useful for debugging)
- Prometheus + redis_exporter: For metrics collection and alerting
- Redis insight: GUI tool for monitoring, includes loading status
Cluster and Sentinel Considerations
- In Redis Cluster, each shard loads independently. One shard loading doesn't affect others.
- Redis Sentinel automatically fails over to a healthy replica, bypassing the loading replica entirely.
- For guaranteed zero-downtime, deploy Sentinel + multiple replicas, and adjust client routing to skip loading instances.
Cloud Provider Notes
- AWS ElastiCache: Managed, automatic persistence without your involvement
- Azure Redis Cache: Imports/exports data through Azure blobs, may show LOADING during import
- Google Cloud Memorystore: Single master mode; replication managed automatically
- DigitalOcean: Managed Redis, uses persistent volumes that may show loading on scale-up
Check your cloud provider's documentation for how they handle LOADING during scale events.
ERR Unbalanced XREAD list of streams
How to fix "ERR Unbalanced XREAD list" in Redis
ERR syntax error
How to fix "ERR syntax error" in Redis
ConnectionError: Error while reading from socket
ConnectionError: Error while reading from socket in redis-py
ERR unknown command
How to fix ERR unknown command in Redis
Command timed out
How to fix 'Command timed out' in ioredis