The Redis Cache That Deleted Our Entire User Session Database at 2 AM

How one misconfigured TTL setting wiped 500K active sessions — and taught me why ‘flush all’ should require a blood oath
The Slack notification arrived at 2:47 AM.
“URGENT: All users logged out. Session service dead. Customer support getting flooded.”
I stared at my phone screen, half-awake, brain refusing to process the words.
500,000 active sessions. Gone. Vanished. Like they never existed.
My Redis cache — the one I’d been so proud of, the one that was “perfectly configured,” the one I’d shown off in last month’s architecture review — had just committed mass murder on our user sessions.
And I was about to find out it was entirely my fault.
How I Became Overconfident with Redis
Six months earlier, I’d been the hero.
Our authentication service was slow. Login took 4 seconds. Every page load hit the database to validate sessions. Users complained. Stakeholders weren’t happy.
I pitched Redis. “In-memory cache. Sub-millisecond reads. Problem solved.”
Two weeks later: login dropped to 200ms. Page loads felt instant. My manager called it “impressive work.” I felt like a goddamn infrastructure wizard.
The problem? I’d learned just enough Redis to be dangerous.
I knew SET and GET. I knew EXPIRE. I even knew about Redis persistence and replication.
What I didn’t know: the 47 ways Redis can silently destroy your data if you configure it wrong.
Red flag #1: When your entire team trusts you with production infrastructure based on one successful implementation.
The “Optimization” That Destroyed Everything
It started innocently. Our Redis memory usage was climbing. 8GB. 12GB. 16GB.
“We’re storing too many sessions,” I thought. “Let me add some automatic cleanup.”
I wrote this configuration:
# Session cleanup - seemed smart at the time
maxmemory 20gb
maxmemory-policy allkeys-lru
save 900 1
save 300 10
```
In my head: "Perfect. Automatically evict old sessions when we hit 20GB. Save to disk periodically. Production-ready."
What I didn't understand:
- `allkeys-lru` doesn't just remove expired keys — it removes ANY keys when memory is full
- My TTL settings weren't consistent across session types
- Some sessions had NO TTL at all
- Redis was making eviction decisions I didn't authorize
I deployed on a Friday afternoon. Because I'm apparently a masochist who enjoys weekend incidents.
**Red flag #2:** Deploying infrastructure changes on Friday at 4:30 PM without a full rollback plan.
## The 2 AM Disaster Unfolds
Monday night, 2:47 AM. The phone buzzes.
By the time I got to my laptop, Slack was a warzone:
```
@channel CRITICAL: Users can't stay logged in
Support: 200 tickets in 10 minutes
Payment team: Checkout broken, sessions expiring mid-purchase
CEO (yes, the CEO): "What's happening with the site?"
I SSH’d into the Redis instance.
redis-cli INFO memory
```
```
used_memory_human:19.8GB
maxmemory_human:20GB
evicted_keys:487,392
My blood turned to ice.
487,392 evicted keys.
Not expired. Not TTL’d. Evicted. Redis had decided our user sessions were “least recently used” and deleted them to stay under 20GB.
Half a million users, logged out simultaneously, because I thought I was smart enough to configure Redis without reading the documentation.
The Panic of Discovery
I did what every engineer does in crisis mode: I Googled frantically.
“redis evicted all sessions”
“maxmemory-policy delete sessions”
“redis allkeys-lru disaster”
The Stack Overflow results were… educational. And terrifying.
Every answer said the same thing: “allkeys-lru will delete ANYTHING when you hit maxmemory, regardless of TTL or importance.”
One comment burned into my brain:
“Using allkeys-lru on session data is like giving Redis a loaded gun and hoping it shoots the right keys. It won’t.”
The CEO pinged me directly: “How long until this is fixed?”
I had no idea. Because I’d just learned my entire mental model of Redis was wrong.
The 3-Hour Recovery Hell
2:52 AM: Disabled the eviction policy:
redis-cli CONFIG SET maxmemory-policy noeviction
Problem: This didn’t bring sessions back. They were gone. I’d just stopped the bleeding.
3:15 AM: Realized we had no session backup. Redis persistence was saving the CURRENT state — which was “sessions deleted.”
3:40 AM: Emergency decision: Force all users to re-login. Update the session service to handle mass re-authentication.
4:20 AM: Deployed session service hotfix:
// Emergency session rebuild
@PostMapping("/auth/recover")
public ResponseEntity<SessionResponse> recoverSession(
@RequestHeader("Authorization") String token
) {
try {
// Validate JWT even if Redis session missing
User user = jwtService.validateToken(token);
// Rebuild Redis session
String sessionId = UUID.randomUUID().toString();
SessionData session = new SessionData(user, sessionId);
// This time with PROPER TTL
redisTemplate.opsForValue()
.set("session:" + sessionId, session,
Duration.ofHours(24));
return ResponseEntity.ok(new SessionResponse(sessionId));
} catch (Exception e) {
return ResponseEntity.status(401).build();
}
}
5:30 AM: Systems recovering. Users logging back in. Incident “resolved.”
Cost:
- 3 hours downtime
- 500K user sessions destroyed
- 847 abandoned shopping carts
- Estimated revenue loss: $43,000
- My reputation with the CEO: also destroyed
What I Learned (The Hard Way)
1. allkeys-lru Is Not a Session Cache Policy
Never use allkeys-lru for session data. Ever. Use volatile-lru or noeviction.
# WRONG - Deletes anything
maxmemory-policy allkeys-lru
# RIGHT - Only deletes keys with TTL
maxmemory-policy volatile-lru
# SAFEST - Fails writes instead of deleting
maxmemory-policy noeviction
2. Every Session Needs an Explicit TTL
Some of my sessions had TTL. Some didn’t. Redis couldn’t tell which were important.
// WRONG - No expiration
redisTemplate.opsForValue().set("session:" + id, session);
// RIGHT - Always set TTL
redisTemplate.opsForValue().set(
"session:" + id,
session,
Duration.ofHours(24)
);
3. Redis Persistence Doesn’t Mean “Backup”
I thought save 900 1 meant “backup my data every 15 minutes.”
It doesn’t. It means “save the CURRENT state.” If the current state is “everything’s deleted,” that’s what gets saved.
Real backups require:
- Separate backup instance
- Periodic RDB snapshots to S3
- AOF logs for point-in-time recovery
4. Memory Limits Are Hard Limits
When Redis hits maxmemory, it WILL delete data (or fail writes). There’s no “please be careful” mode.
Monitor memory usage. Alert at 80%. Scale before you hit the limit.
5. Test Your Cache Failure Mode
I never asked: “What happens if Redis deletes all sessions?”
The answer: total authentication collapse.
Now we have:
- Fallback to database sessions (slow but functional)
- Circuit breakers that degrade gracefully
- JWT validation that works without Redis
The Infrastructure Changes We Made
1. Monitoring that actually works:
# Alert when evictions start happening
redis-cli INFO stats | grep evicted_keys
# Alert at 80% memory
redis-cli INFO memory | grep used_memory_human
2. Proper eviction policy:
maxmemory 40gb # Higher limit
maxmemory-policy volatile-lru # Only evict keys with TTL
3. Real backups:
# Hourly RDB snapshots to S3
0 * * * * redis-cli BGSAVE && aws s3 cp /var/lib/redis/dump.rdb s3://backups/redis/
# AOF for point-in-time recovery
appendonly yes
appendfsync everysec
4. Session service resilience:
@Service
public class SessionService {
public Optional<Session> getSession(String id) {
// Try Redis first
Optional<Session> cached = getFromRedis(id);
if (cached.isPresent()) return cached;
// Fallback to database
return sessionRepository.findById(id)
.map(session -> {
// Rebuild cache
rebuildCache(session);
return session;
});
}
}
The Postmortem Nobody Wanted to Write
The incident postmortem was… uncomfortable.
Timeline:
- 02:47 — Mass session eviction detected
- 02:52 — Root cause identified (allkeys-lru + maxmemory)
- 03:40 — Decision: force re-login for all users
- 04:20 — Session recovery service deployed
- 05:30 — Systems stable, users recovering
Root cause: Engineer (me) configured Redis eviction policy without understanding LRU vs TTL-based eviction.
Impact:
- 500K users logged out
- $43K revenue loss from abandoned carts
- 3 hours degraded service
Prevention:
- Never use allkeys-lru on session data
- Require explicit TTL on all cached sessions
- Implement database fallback for cache failures
- Test failure modes in staging
The CEO asked one question: “How did this get to production without anyone catching it?”
The answer: Because I was confident. And confidence without knowledge is just arrogance waiting to fail.
The Real Cost of “Move Fast and Break Things”
This incident taught me something uncomfortable: Redis doesn’t care about your confidence.
It does exactly what you configure it to do. If you configure it wrong, it will faithfully destroy your data at 2 AM.
The myth: “I deployed Redis successfully, so I understand Redis.”
The reality: I understood one narrow use case. Everything outside that? Landmines.
How I Use Redis Today
Six months later, here’s my Redis checklist:
✅ What I Always Do:
- Use volatile-lru or noeviction for session caches
- Set explicit TTL on every cached value
- Monitor eviction rate and alert at > 0
- Test cache failure scenarios
- Backup RDB snapshots to S3 hourly
- Keep fallback to database for critical paths
❌ What I Never Do:
- Use allkeys-lru on production data
- Deploy cache changes on Friday
- Trust Redis persistence as “backup”
- Assume “it works in dev” means “it works at scale”
The Pattern Nobody Talks About
Most Redis disasters follow the same script:
- Engineer learns Redis basics
- Deploys successfully for small use case
- Gains confidence, takes on bigger problems
- Skips reading documentation (“I know Redis now”)
- Configures advanced features based on vibes
- Production scales past safe limits
- Disaster
Sound familiar?
I wasn’t unlucky. I was undertrained and overconfident.
The Resources That Actually Help
Want to avoid my mistakes? These resources filled my knowledge gaps:
Critical Reading:
- Redis in Production — The TTL vs eviction section could’ve saved me $43K
- Production Incident Prevention Kit — Checklist for cache failure modes
- On-Call Survival Kit — What to do when Redis deletes everything at 2 AM
For Your Next Incident:
When (not if) your next production incident hits, you need root cause analysis fast.
I built ProdRescue AI after too many 3 AM debugging sessions. Paste your logs or connect Slack → get root cause, timeline, and suggested fixes in 2 minutes.
No more digging through 200 Slack messages. No more manual RCA write-ups. Just evidence-backed clarity when you need it most.
Join My Newsletter:
I write about real production incidents like this one every week.
👉 Subscribe to my Substack — Real backend disasters, lessons learned, and how to avoid them.
Still Copying Configuration from Stack Overflow?
Redis killed my sessions because I thought documentation was optional.
Spoiler: It’s not.
Your production cache is one misconfigured eviction policy away from deleting everything. Learn the failure modes before they learn you.
What’s your Redis horror story? Drop it in the comments. I promise you’re not alone.
The takeaway: allkeys-lru on session data is a production incident waiting to happen. Don’t be me. Read the docs. Test the failure modes. Sleep better.
The Redis Cache That Deleted Our Entire User Session Database at 2 AM was originally published in Javarevisited on Medium, where people are continuing the conversation by highlighting and responding to this story.
This post first appeared on Read More

