Idle RDS instances: How to Find Them and What They Cost

Idle RDS instances are database instances with no connections, billing compute and storage around the clock — often in non-production environments nobody switched off. They are one of the most reliable sources of pure waste in an AWS account, because nothing in the console flags them and nothing fails when they exist — the bill simply stays higher than it needs to be.

This page covers what they cost, the command that lists yours, and — importantly — what to check before deleting anything.

What they are and why they linger

An RDS instance bills for compute by the hour, for allocated storage by the gigabyte-month, for provisioned IOPS where applicable, and for backup storage above the free allowance. None of that stops when connection count drops to zero.

The population is predictable: development and staging databases created for a project that finished, read replicas promoted and forgotten, and Multi-AZ standbys on non-production instances that never needed high availability.

What they cost

A db.m5.large Multi-AZ instance is roughly $250 a month before storage. Three of them in a decommissioned staging environment is $9,000 a year.

Multi-AZ on non-production is its own line: it exactly doubles the compute charge to protect a database whose loss would cost nothing.

Finding yours

# Every instance with its class and Multi-AZ setting.
aws rds describe-db-instances \
  --query 'DBInstances[].{Id:DBInstanceIdentifier,Class:DBInstanceClass,MultiAZ:MultiAZ,Storage:AllocatedStorage,Status:DBInstanceStatus}' \
  --output table

# Peak connection count over the last two weeks. Zero means nothing uses it.
for db in $(aws rds describe-db-instances --query 'DBInstances[].DBInstanceIdentifier' --output text); do
  max=$(aws cloudwatch get-metric-statistics --namespace AWS/RDS \
    --metric-name DatabaseConnections --dimensions Name=DBInstanceIdentifier,Value="$db" \
    --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 1209600 --statistics Maximum \
    --query 'Datapoints[0].Maximum' --output text)
  echo "$db: peak ${max:-0} connections in 14 days"
done

Pair that with CPUUtilization — an instance with a handful of connections and 2% CPU is a right-sizing candidate even if it is genuinely in use.

Before you delete

Take a final snapshot before deleting. --final-db-snapshot-identifier is not optional in spirit even when it is in syntax:

aws rds delete-db-instance --db-instance-identifier my-old-db \
  --final-db-snapshot-identifier my-old-db-final-$(date -u +%Y%m%d)

A connection count of zero does not always mean unused. Check for scheduled jobs, quarterly reporting, and disaster-recovery roles before deleting. And confirm nothing holds the endpoint in configuration — a service that fails to start next quarter because a database vanished is a worse outcome than the bill.

Stopping is not a complete answer. A stopped RDS instance still bills for storage and backups, and RDS automatically restarts it after seven days. For a database that is needed occasionally, snapshot and delete, then restore when needed — the snapshot costs a fraction of the instance.

Stopping them coming back

Give non-production databases a lifecycle: created by the same IaC as the environment, destroyed with it. Where they must persist, schedule stop/start around working hours with EventBridge, and turn Multi-AZ off outside production.

Aurora Serverless v2 scales down to a low floor for intermittent workloads and removes the “someone forgot to stop it” failure mode entirely.


Prices quoted are us-east-1 list rates, last checked on 2026-08-22, and are shown with the arithmetic so you can substitute the rates for your own region. Always confirm against the AWS pricing page before acting on a number.