How-to guide

Find and remove idle resources in AWS

Learn how to find idle AWS resources with Cost Explorer, CloudWatch, and AWS Config, then remove them safely with checks and tags.

By the Cloudverg engineering team · · 6 min read

Why this matters

Idle resources are assets that do no useful work but still create charges. Common examples in AWS include unattached EBS volumes, unassociated Elastic IP addresses, load balancers with no traffic, NAT gateways with no active connections, stopped EC2 instances that keep their volumes, old EBS snapshots, and CloudWatch log groups with no retention setting.

They collect after experiments, migrations, and incident fixes. A team spins up a test stack, forgets the load balancer, and moves on. The bill grows in small lines that no one owns. Cost per product becomes harder to trust, and security reviews waste time on resources that no application uses. A clean inventory also makes tagging and budget alerts more accurate.

Removal is risk work. Some idle-looking resources are backups, DNS targets, failover capacity, or held for an audit. Treat the first pass as triage. Confirm the owner, the last real activity, and the restore path. Delete only when you have evidence and either a backup or a clear sign-off from the owner.

Before you start

Pick the accounts and Regions in scope. Get read-only access through an IAM role or IAM Identity Center permission set, not a shared access key. Turn on Cost Explorer and activate cost allocation tags. Find the owners for production, finance, and security, and agree on a change window before anything is removed.

Create one record for each candidate. Capture the resource ARN, account, Region, service, tags, reason for review, owner, planned action, backup plan, and review date. Use AWS Resource Explorer to search across Regions, and use Cost Explorer or the Cost and Usage Report to connect a resource to spend.

Check the guardrails. CloudTrail should be on in all Regions, AWS Config should record resource changes, and AWS Backup should cover data you may need to restore. Look for termination protection, deletion protection, and retention policies. Start with orphaned storage and addresses. Leave shared network and databases for the second pass.

How to do it

First find resources with no attachment or no owner. Then check traffic and activity over time. Then remove the clear cases and tag the rest for review. Keep the evidence with the ticket so a later reviewer can see why a resource was deleted.

Use native filters before you write scripts. The EC2 console can show volumes in the available state and Elastic IP addresses with no association. CloudWatch metrics show traffic for load balancers and NAT gateways. CloudTrail event history shows who last changed a resource. Cost Explorer shows the service and tag view, but it will not prove that a single resource is idle.

Remove in a safe order. Snapshot or back up first when data is involved. Remove DNS records and allowlist entries before releasing an address. Delete the resource, then remove the backup after the retention date. Record the change and tell the owner. A short wait period between tagging and deletion catches mistakes.

Close the loop with controls. Add AWS Config rules for required tags and resource state. Use Instance Scheduler for nonproduction EC2 and RDS schedules. Add S3 lifecycle rules to abort incomplete multipart uploads and expire old objects. Set CloudWatch log retention. Add AWS Budgets alerts so a new idle resource does not run for months.

  1. Inventory accounts and Regions. List every account and Region in scope, including sandbox and old workload accounts. Use AWS Resource Explorer to search by service, tag, and state, and export the results to your tracking ticket. Record the ARN, owner tag, and last change date for each candidate.
  2. Find unattached EBS volumes. Open the EC2 console, choose Volumes, and filter State to available. Sort by creation date and check CloudTrail for the detach event and the instance that used the volume. If the data may be needed, create a snapshot and set a delete date before you remove the volume.
  3. Release unassociated Elastic IPs. Open Elastic IPs and check for an empty Association ID. Look in Route 53 for DNS records that point to the address and ask the owner about partner allowlists. Release the address only after those checks and after you record the old address in the ticket.
  4. Check stopped instances and idle load balancers. Stopped EC2 instances still hold EBS volumes. Create an AMI if the instance may be needed, then terminate it and remove orphaned volumes. For load balancers, use CloudWatch RequestCount, ActiveConnectionCount, and target health over at least two weeks.
  5. Review NAT gateways, RDS, and log groups. For NAT gateways, check ActiveConnectionCount and BytesOutToDestination over a full business cycle. For RDS, check DatabaseConnections and CPUUtilization, and remember that a stopped database starts again after seven days. Set retention on CloudWatch log groups or delete groups that no application writes to.
  6. Confirm activity and owner. Use CloudTrail event history for API calls and CloudWatch for traffic. Add tags such as review-status, keep-until, and owner, then notify the owner with the planned date. Wait for a response or for the keep-until date before deletion.
  7. Remove with a backup and a record. Take an on-demand backup or snapshot when data is involved. Remove DNS and allowlist entries, delete the resource, and update the ticket with the time, actor, and result. Keep the backup until its retention date, then delete it in a later pass.

How to check it worked

Compare Cost Explorer before and after. Filter by service and by the tag you used for the cleanup. Use daily granularity and look at the next full billing period, since billing data can lag. The Cost and Usage Report gives line-item detail if you need to prove which resource changed.

Count the resources again. Check for EBS volumes in the available state, unassociated Elastic IPs, load balancers, NAT gateways, RDS instances, and log groups without retention. AWS Resource Explorer can run the same queries across accounts and Regions. AWS Config should show the expected compliance state for your tag and lifecycle rules.

Test recovery and watch for breakage. Restore one snapshot to a temporary volume and attach it to a test instance. Check application logs, DNS resolution, and CloudTrail for unexpected Delete or Release calls. Recheck after one week and again after the next bill.

Mistakes to avoid

Do not delete on one metric. A load balancer can be quiet at night and busy at month end. A NAT gateway can carry batch traffic once a week. Check CloudWatch and CloudTrail over a full business cycle, and ask the owner about seasonal jobs before you act.

Do not treat a stopped EC2 instance as free. Its EBS volumes still exist and still cost money, and the instance can restart with old settings. RDS stop is temporary and the database starts again after seven days. Snapshots and AMIs also carry storage charges, so a backup plan needs its own retention date.

Do not break shared network paths. A NAT gateway may be the only route out for private subnets. A load balancer may sit behind a Route 53 alias. An Elastic IP may be in a partner allowlist. Check dependencies and DNS before release, and remove during a window when the owner can respond.

Do not remove without an owner. Use the Resource Groups Tag Editor to find missing owner tags and send a review notice. You can run this work with the steps above, use AWS cost tools, hire a consultant, or start with a fixed scope review such as the Cloudverg Cloud cost audit package at $4,500 fixed price.

Frequently asked questions

Which AWS resources are most often idle?

Unattached EBS volumes, unassociated Elastic IPs, idle load balancers, NAT gateways with no connections, stopped EC2 instances with volumes, old EBS snapshots, and log groups without retention. Check last activity and owner before you delete any of them.

Can I delete a stopped EC2 instance safely?

A stopped instance still keeps its EBS volumes and can restart. Create an AMI or snapshot, confirm that no Auto Scaling group or launch template will recreate it, then terminate it. Check termination protection first.

How long should I watch a resource before calling it idle?

Watch at least one full business cycle, such as two to four weeks, and include month-end jobs. For batch or seasonal workloads, use CloudTrail and CloudWatch history over a longer period. If the pattern is unclear, tag the resource for owner review instead of deleting it.

Fixed price

Want help with this? Cloud cost audit

$4,500 fixed price

2 weeks · Starts within 10 business days

A two-week, read-only review of your AWS, Azure, Google Cloud or Oracle bill, with every saving ranked by dollars per month.

What is included

Related guides

More cloud costs guides   Cloud cost audit

Smallest way to start

Get a senior architect on your problem this week

Ninety minutes on the cloud, AI or security question that is blocking you, a pre-read of your material and a written summary within two business days.

$450 one-time