Are You Paying for an Idle ElastiCache (Redis) Cluster?

An idle ElastiCache node bills exactly the same as a busy one — from ~$12/mo per node. How to prove a Redis cluster is unused, then delete it safely.

Published July 25, 2026 · Last updated August 12, 2026

Somewhere in your account there is probably a Redis cluster called something like sessions-staging or api-cache-v2. It was spun up for a feature that shipped differently, or for an environment that got rebuilt, and nothing has connected to it in months. It is still available, still healthy, still green in the console — and still billing, every hour, at exactly the same rate as the cache your production traffic depends on. ElastiCache is one of the easiest AWS services to forget about, because a cache that nobody uses looks identical to a cache that's working perfectly. This post shows you how to tell the difference, and what to do about it.

Why does an idle Redis cluster cost the same as a busy one?

ElastiCache bills node-hours. You pay for the node type you provisioned, for every hour it exists, regardless of how many commands it serves. A cache.t3.micro costs about $12.41 a month in us-east-1 whether it handles fifty thousand operations a second or zero. There is no idle rate, no scale-to-zero, and — unlike an EC2 instance — no stop button. A cache either exists and bills, or it's deleted.

That flat model is what makes forgotten caches expensive out of proportion to how harmless they look. The meter runs on provisioned time, not usage, the same trap as an idle load balancer or a NAT Gateway nobody routes through anymore.

Two things turn "annoying" into "actually worth an afternoon":

  • Node type. The small end is cheap — cache.t3.micro at ~$12.41/month, cache.t3.small at ~$24.82. The memory-optimised end is not: a single cache.r6g.large is roughly $164.98/month, and an r6g.2xlarge is around $659.92. A forgotten cache sized for a production workload it never received is a four-figure annual line item.
  • Replicas multiply it. The charge is per node, so a replication group with a primary and two replicas costs three times the node price. Delete the cluster and you reclaim all of it, not a third.

What actually counts as "idle" for a cache?

This is where people get it wrong, and it's worth being precise, because the wrong signal leads to the wrong fix.

The instinct is to look at CPU. Don't — at least not first. A Redis node sitting at 3% CPU might be idle, or it might be serving a low-cost read-heavy workload very efficiently. Redis is fast; low CPU is normal for caches that are genuinely in use. If you delete on CPU alone you will eventually delete something a service quietly depends on.

The signal that actually separates "unused" from "efficient" is client connections. An application that uses a cache holds connections open to it. A cache with essentially no connections has no clients — that's not efficiency, that's abandonment. So the definition worth acting on is:

Idle = an available cluster whose average CurrConnections is effectively zero (under ~0.5) across a 14-day window, and that has existed for at least 14 days.

Both halves of that matter. Fourteen days is long enough to survive a weekly batch job or a cron that only fires on Sundays — a cache can look dead on a Tuesday and be genuinely used on a Sunday night. And the age guard keeps a cluster someone provisioned yesterday, before pointing the app at it, from being flagged as waste.

There's a second, different problem that also shows up as low numbers: a cluster that is connected and serving traffic, but on a node type far larger than it needs. That's not idle, it's over-provisioned, and the fix is to downsize rather than delete. In practice the split is: near-zero connections → delete; real connections but low engine CPU (say, under 15%) and low memory usage (under ~30% of the node's capacity) → resize down a step. Mixing them up means either paying for headroom you never use or deleting a cache something still needs.

How do I confirm a cluster is unused?

Start by listing what you actually have, including node type and count — this alone usually surfaces a cluster or two nobody on the team recognises:

# Every cluster with its node type, node count, engine, and status
aws elasticache describe-cache-clusters \
  --query 'CacheClusters[].[CacheClusterId,CacheNodeType,NumCacheNodes,Engine,CacheClusterStatus,ReplicationGroupId]' \
  --output table \
  --region us-east-1

Then check connections over two weeks. This is the decisive metric — a flat line at or near zero means no client has been talking to this cache:

aws cloudwatch get-metric-statistics \
  --namespace AWS/ElastiCache \
  --metric-name CurrConnections \
  --dimensions Name=CacheClusterId,Value=sessions-staging \
  --start-time "$(date -u -d '14 days ago' +%Y-%m-%dT%H:%M:%SZ)" \
  --end-time "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
  --period 86400 \
  --statistics Average Maximum \
  --region us-east-1 \
  --output table

Read both statistics, not just the average. Average near zero with a Maximum of 40 on one day means something connects periodically — a nightly job, a scheduled report — and the cache is used, just not continuously. Average and maximum near zero across all fourteen days is your confirmation.

For corroboration, pull EngineCPUUtilization (the Redis engine's own CPU, more meaningful than host CPUUtilization on a multi-core node) and CacheHits. Zero hits and zero misses over two weeks means nothing has asked this cache for anything at all. Swap the metric name in the command above and re-run it.

How do I delete it safely?

Before you delete anything, do the boring check that saves you: look at the tags and find the owner.

# Cluster ARN format: arn:aws:elasticache:<region>:<account-id>:cluster:<cluster-id>
aws elasticache list-tags-for-resource \
  --resource-name arn:aws:elasticache:us-east-1:123456789012:cluster:sessions-staging \
  --region us-east-1

A team, owner, or environment tag tells you who to ask. Untagged clusters are the ones most likely to be genuinely abandoned — and also the ones where a two-minute Slack message is cheapest insurance.

With the owner confirmed and connections proven flat, delete it. For a standalone cluster, take a final snapshot if there is any chance you want the keys back:

# Standalone cluster (no ReplicationGroupId in the listing above)
aws elasticache delete-cache-cluster \
  --cache-cluster-id sessions-staging \
  --final-snapshot-identifier sessions-staging-final \
  --region us-east-1

# Cluster that is part of a replication group — delete the group instead
aws elasticache delete-replication-group \
  --replication-group-id sessions-staging-rg \
  --final-snapshot-identifier sessions-staging-rg-final \
  --region us-east-1

Billing stops when the cluster is gone. Snapshots themselves are cheap storage, but they aren't free — set a reminder to delete the final snapshot once you're confident nobody wants it. If you'd rather click, the Console path is ElastiCache → Redis caches → select → Actions → Delete.

If the cluster turns out to be used but oversized, don't delete it — modify the node type instead, during a maintenance window, and watch evictions and hit rate afterward. See Over-provisioned ElastiCache node type for how we size that recommendation.

What else should I check while I'm in here?

Caches rarely idle alone. A cache with no connections usually means the service in front of it is gone — so the database behind it is often idle or oversized too, and that's typically the bigger number. The same "provisioned for a peak that never came" pattern runs straight through the data tier: an r6g.large cache nobody queries frequently sits next to an RDS instance running at 8% CPU.

So while you have the account open, do the database pass as well — see how to right-size an over-provisioned RDS instance without downtime, which also covers the important distinction between "idle" and "merely oversized" and the RDS gotcha where a stopped instance restarts itself after seven days.

The analytics tier is worth the same look, and it is usually the bigger number: a Redshift cluster left running for a dashboard nobody opens costs from ~$365/month, and unlike ElastiCache it can be paused without losing anything — see how to cut Redshift costs by pausing idle clusters.

How do I find every idle cache across my account?

Checking one cluster by hand is a ten-minute job. Doing it for every ElastiCache cluster in every region, pulling fourteen days of connection and CPU history for each, telling a genuinely dead cache from a quiet-but-load-bearing one, and then re-checking next quarter when someone rebuilds staging again — that's the tedious part, and it's exactly where these charges survive. Caches are one stop on that circuit; the wider guide to cutting an AWS bill lays out the rest of it and which passes are worth doing first. That's what a scan is for. Parsivex checks each region, flags clusters with no client connections against real 14-day metrics, separates them from ones that are merely over-provisioned, and then keeps watching, so the next forgotten cache doesn't quietly bill for a year.

For what these findings mean once they show up in your report, see Idle ElastiCache cluster, or read how scans work before you connect an account.