AWS cost · EBS
Unattached EBS volumes still bill $0.08/GB-month
EBS shows an unattached volume as available. It reads like spare capacity waiting to be used. It is an ordinary billing state: the volume was provisioned, so it is charged, and having no instance on the other end changes nothing.
A 500 GiB gp3 volume attached to nothing costs about $40/month in us-east-1, and the same volume on gp2 costs $50. The status that means nobody is using it bills exactly what being used bills.
What a volume nobody uses costs
| What | Cost | Note |
|---|---|---|
| 500 GiB gp3, attached to nothing | ~$40.00/month | $0.08/GiB-month, us-east-1 |
| 500 GiB gp2, attached to nothing | ~$50.00/month | $0.10/GiB-month - the older default |
| A volume on a stopped instance | full price | the instance bills $0, the disk does not |
| The same data as a snapshot | $0.05/GB-month or less | incremental, so usually far less |
Two ways a disk ends up billing for nothing
The first is the unattached volume. Terminating an instance deletes its root disk, which defaults to delete-on-termination. Any volume added afterwards defaults the other way and outlives the instance. A detach during a migration does the same thing more quietly, because nothing was deleted and nothing looks wrong.
The second is a volume still attached to a stopped instance. Stopping ends the instance-hour charge and nothing else, so the disk bills at full rate while the EC2 line on the bill goes quiet. Both are the same leak; only one of them appears in a list of unused resources.
How to find both
# volumes attached to nothing
aws ec2 describe-volumes --filters Name=status,Values=available \
--query 'Volumes[].{Id:VolumeId,GiB:Size,Type:VolumeType,Created:CreateTime,Az:AvailabilityZone}' \
--output table
# volumes parked on a stopped instance - same charge, different place
aws ec2 describe-instances --filters Name=instance-state-name,Values=stopped \
--query 'Reservations[].Instances[].{Id:InstanceId,Vols:BlockDeviceMappings[].Ebs.VolumeId}' \
--output jsonRead the creation date alongside the size. A 16 GiB volume detached last Tuesday is somebody mid-task; a 500 GiB volume that has been available since 2023 is not.
What deleting costs
Deleting a volume is irreversible and takes the data with it. The cheap insurance is a snapshot: storage drops to $0.05/GB-month, and because snapshots are incremental and compressed the stored size is normally well under the volume size. You keep the ability to restore, at a fraction of the price.
Two things the snapshot does not solve. Restoring creates a new volume with a new id, so anything referencing the old one by id needs updating. And snapshots outlive the volume and keep billing on their own. That is how a tidy-up becomes a pile of orphaned snapshots two years later.
# MUTATING - snapshot first, then delete. The delete cannot be undone.
aws ec2 create-snapshot --volume-id vol-0123456789abcdef0 \
--description "pre-delete, unattached since 2023"
aws ec2 delete-volume --volume-id vol-0123456789abcdef0If the volume is in use and just on the wrong type, do not delete it - switching gp2 to gp3 takes 20% off the same disk with no downtime.
Want to know which disks are billing for nothing, attached or not? Connect your account read-only and see what it is wasting, in real dollars.
The role can only read - Get, Describe, List, nothing else. Read the exact permissions before you deploy it, and delete the stack whenever you want.
Frequently asked questions
Do unattached EBS volumes cost money?+
Yes, the full rate. An EBS volume bills for provisioned capacity, not for use, so a volume in the available state costs exactly what it would cost attached to a busy instance. A 500 GiB gp3 volume is about $40/month in us-east-1 whether anything reads it or not.
Why do I have volumes attached to nothing?+
Two routes, mostly. Terminating an instance leaves behind any volume whose delete-on-termination flag was off - which is the default for volumes you add rather than the root disk. And a volume detached during a migration or a recovery stays detached until somebody remembers it.
Does stopping an instance stop its disk charges?+
No. Stopping ends the instance-hour charge and nothing else. The EBS volumes stay provisioned and keep billing at the full rate, which is why a fleet of stopped instances can cost real money while the EC2 line on your bill looks fine.
Is it cheaper to keep a snapshot than the volume?+
Usually much cheaper. Snapshot storage is $0.05/GB-month in us-east-1 against $0.08 for gp3, and snapshots are incremental and compressed, so the stored size is normally well below the volume size. The trade-off is that restoring a snapshot creates a new volume, which takes minutes and gives you a new volume id.
How do I know a volume is safe to delete?+
You do not, from the API alone. An available volume tells you nothing about whether someone plans to reattach it next week. Check the tags, check when it was detached, and take a snapshot before deleting - that turns an irreversible action into a slow one.
Does deleting a volume delete its snapshots?+
No. Snapshots are independent of the volume they came from and keep billing after the volume is gone. That is a feature when you snapshot before deleting, and a cost when nobody ever cleans the snapshots up.
Related cost breakdowns
ECR storage costs $0.10/GB - and CI builds pile it up
ECR stores container images at $0.10/GB-month, and every CI build pushes layers that never expire on their own. Without a lifecycle policy the bill climbs forever - here is how to cap it.
Orphaned EBS snapshots are quietly draining your AWS bill
EBS snapshots cost $0.05/GB-month and never delete themselves. Forgotten ones pile up into hundreds a month. Here is how to find the orphans and automate cleanup.
Why your S3 bill keeps growing - and how to stop it
Cold backups sit in S3 Standard at ~$46/month per 2 TB when Glacier Deep Archive is ~$2/month for the same files. One lifecycle rule moves them automatically.
Switch EBS gp2 to gp3 and cut 20% with no downtime
gp3 volumes cost $0.08/GB-month against gp2's $0.10 - 20% less at the same or better performance, with a live migration and no downtime. Here is the one command.