How to find unused AWS resources
Four things go on being billed in AWS long after anyone uses them: EBS volumes attached to no instance, Elastic IPs associated with nothing, EC2 instances that barely run, and RDS instances nothing connects to. All four can be found with AWS's own features. The work is in repeating the same check region by region and account by account. What follows is, in order, how to find each one with the AWS CLI and what to check before deleting it. The region, the instance IDs, the DB identifiers and the dates in the commands are examples: replace them with the values from your own environment.
Last updated: 2026-09-22
Why they stay behind
Deleting an EC2 instance does not always take its EBS volume with it: depending on the settings, the volume stays. An Elastic IP allocated for a test stays allocated after the instance is gone, until someone releases it. A test environment nobody remembered to stop, or the old database left behind after a migration, keeps running and keeps being billed while nobody uses it.
Each one costs so little on its own that it never shows up in the invoice, so nothing draws attention to it; and once whoever created it changes teams or leaves the company, it sits there as something nobody is sure it is safe to delete.
What to know before you look
EC2, EBS, Elastic IP and RDS are per-region resources. The console and the CLI alike show only what is in the region you are looking at, so what was left behind in a region nobody works in is exactly what gets missed. Repeat the steps below in every region that is enabled.
Since February 2024, every public IPv4 address is billed at $0.005 per hour whether it is in use or not. An Elastic IP associated with nothing goes on costing that while doing no work at all, which makes it the first thing to clear out of the way.
Find unattached EBS volumes
A volume whose state is available is attached to no instance. In the console, filter by state under “Volumes” in EC2. From the CLI, this command lists them.
aws ec2 describe-volumes --region ap-northeast-1 --filters Name=status,Values=available --query 'Volumes[].[VolumeId,Size,VolumeType,CreateTime]' --output tableBefore deleting one, check whether it could still be needed. The name tag and the creation time often say what it was for. If you cannot tell, taking a snapshot and only then deleting the volume leaves, in most cases, a way back at a lower storage cost.
Find unused Elastic IPs
An address that carries no association ID is an unused Elastic IP.
aws ec2 describe-addresses --region ap-northeast-1 --query 'Addresses[?AssociationId==`null`].[PublicIp,AllocationId]' --output tableThere is no guarantee that a released address can be got back. Before releasing one, check that it is not in a DNS record or on the firewall allow list of a customer or a partner.
Find EC2 instances that barely run
Look at CloudWatch's CPUUtilization averaged over roughly two weeks. Replace the start and end times with the 14 days leading up to the day you run it. What the command returns is a single average for the whole period. An instance whose average does not reach a few per cent is a candidate for being unused, or for being larger than it needs to be.
aws cloudwatch get-metric-statistics --region ap-northeast-1 --namespace AWS/EC2 --metric-name CPUUtilization --dimensions Name=InstanceId,Value=i-0123456789abcdef0 --start-time 2026-09-06T00:00:00Z --end-time 2026-09-20T00:00:00Z --period 1209600 --statistics AverageTake care not to decide on CPU alone. A batch job that runs once a month, a standby machine or a bastion host are all needed even with a low average CPU. Look at network transfer alongside it and, in the end, ask the people who use it. With AWS Compute Optimizer enabled, it is AWS itself that puts forward the idle and oversized candidates.
Find RDS instances nothing connects to
Look at CloudWatch's DatabaseConnections averaged over about a week. Here too, replace the dates with the last 7 days. If the average sits below 1, it is very likely that no application is connecting.
aws cloudwatch get-metric-statistics --region ap-northeast-1 --namespace AWS/RDS --metric-name DatabaseConnections --dimensions Name=DBInstanceIdentifier,Value=mydb --start-time 2026-09-13T00:00:00Z --end-time 2026-09-20T00:00:00Z --period 604800 --statistics AverageA stopped RDS instance starts itself again after 7 days. If you are certain it will not be used, the safe course is to take a final snapshot and delete it.
See them all at once with AWS's own features
Instead of checking one by one, you can let AWS's own features put the candidates forward. Cost Optimization Hub gathers idle resources and rightsizing recommendations into one view, each with its estimated saving. Compute Optimizer gives recommendations for EC2, EBS and other services. Trusted Advisor has cost optimisation checks too, but using them needs a Business Support+ support plan or higher.
All of them are enabled and used per account, or per AWS Organizations organization.
Keeping it up across several accounts
None of the checks above is done once and finished. Resources get created every day, so this comes back on a schedule, in every region, once for every account in your care.
Sabaki runs this check by itself, every night, with nothing more than a read-only IAM role. The conditions are: EC2 under 5% average CPU utilisation over the last 14 days, RDS under an average of 1 connection over the last 7 days, EBS in the available state, and Elastic IPs associated with nothing. For every resource it finds it works out a monthly estimate from the On-Demand rates in the AWS price list, and explains in plain English why it counted as waste and what to do about it. The estimate assumes Linux and shared tenancy, and does not include discounts or charges such as RDS storage. The regions it looks at are the ones where cost was incurred in the last 30 days. On Team or above, with several customers' accounts connected, they are laid out customer by customer. Sabaki never deletes anything.
Those four kinds are all it detects. NAT gateways, load balancers, old snapshots and the like are out of scope, so check for those with the AWS features above. On the Free plan (one account), the detection and the savings recommendations are all there. The detail is in AWS cost visibility and savings recommendations.
Connect one read-only role and the first results are there in minutes
The Free plan covers one account and one seat, with no credit card. All it takes is a read-only IAM role: no access keys are registered and no write permissions are asked for.
Related questions
Related guides
If this helps, pass it on to someone who needs it.
