How to find out what's costing money in your AWS account
Updated · 4 min read
The bill is bigger than you expected, and the AWS console has at least three places that talk about money. The quickest route is always the same: find the service, then the usage type (which usually tells you the region too), then the actual thing that's running.
In the AWS console
- Billing and Cost Management → Bills. Pick the month. Charges are listed by service, and inside each service by region and line item, with the amount used. This is the bill itself, so it's always there.
- Cost Explorer, for the trend. Set the range to the last three months, Granularity to Daily and Group by to Service. A step up in the chart shows when something started. Then filter to that service and group by Usage type: names like
USE2-NatGateway-Hoursstart with a short region code (USE2is Ohio). If nobody has opened Cost Explorer in your account before, the first visit turns it on, and the data takes up to a day to appear. - Budgets can email you when spending passes an amount you choose, so next time you hear before the bill does. Cost Anomaly Detection watches for unusual jumps.
With the AWS CLI
Last month by service, biggest first:
aws ce get-cost-and-usage \
--time-period Start=2026-09-01,End=2026-10-01 \
--granularity MONTHLY --metrics UnblendedCost \
--group-by Type=DIMENSION,Key=SERVICE \
--query 'ResultsByTime[0].Groups[].[Keys[0], Metrics.UnblendedCost.Amount]' \
--output text | sort -t$'\t' -k2 -rn | head -15The End date isn't included, so this is all of September. Each Cost Explorer API request costs one cent.
Then break the top service down by usage type:
aws ce get-cost-and-usage \
--time-period Start=2026-09-01,End=2026-10-01 \
--granularity MONTHLY --metrics UnblendedCost \
--filter '{"Dimensions": {"Key": "SERVICE", "Values": ["EC2 - Other"]}}' \
--group-by Type=DIMENSION,Key=USAGE_TYPE \
--query 'ResultsByTime[0].Groups[].[Keys[0], Metrics.UnblendedCost.Amount]' \
--output text"EC2 - Other" is a common surprise: it's where NAT gateways, disks (EBS volumes), snapshots and data transfer end up, separate from the servers themselves.
The usual suspects
Each of these lives in one region, so check every region you use. This guide shows how to loop over regions.
NAT gateways. Each costs about $0.045 an hour in us-east-1 (roughly $33 a month) before any data goes through it, and they're easy to forget in a test VPC.
aws ec2 describe-nat-gateways --filter Name=state,Values=available \
--query 'NatGateways[].[NatGatewayId, VpcId, CreateTime]' --output textPublic IPv4 addresses. Since February 2024 every public IPv4 address costs $0.005 an hour, about $3.60 a month, whether it's in use or not. Elastic IPs that aren't attached to anything:
aws ec2 describe-addresses \
--query 'Addresses[?AssociationId==null].[PublicIp, AllocationId]' --output textDisks left behind when a server was deleted:
aws ec2 describe-volumes --filters Name=status,Values=available \
--query 'Volumes[].[VolumeId, Size, VolumeType, CreateTime]' --output textOld snapshots, often from a backup job nobody remembers setting up:
aws ec2 describe-snapshots --owner-ids self \
--query 'Snapshots[].[SnapshotId, VolumeSize, StartTime]' --output textDatabases nobody uses. RDS charges by the hour whether anyone connects or not, and a stopped RDS database starts itself again after seven days.
aws rds describe-db-instances \
--query 'DBInstances[].[DBInstanceIdentifier, DBInstanceClass, DBInstanceStatus]' --output textLogs kept forever. CloudWatch log groups never expire unless you set a retention period. These have none:
aws logs describe-log-groups \
--query 'logGroups[?retentionInDays==null].[logGroupName, storedBytes]' --output textand this keeps 30 days of one of them:
aws logs put-retention-policy --log-group-name /aws/lambda/my-function --retention-in-days 30Something in a region you never use. A test server, a forgotten function, a tutorial's leftovers. The Bills page lists charges by region, so look for regions you don't recognize.
Or in Cloud GUI
Cloud GUI's Costs page shows this month so far, AWS's forecast for the month and last month, with what each service costs, from Cost Explorer. It keeps the figures for six hours, since AWS bills each Cost Explorer request to your account. The free checkup flags the usual leaks: disks not attached to any server, Elastic IPs not in use, and stopped RDS databases still paying for storage. Cloud GUI also lists your files (S3) and functions (Lambda) from every region in one place, which is often how a forgotten bucket or function in an unexpected region turns up, and its Logs page lists every CloudWatch log group with how much it stores and how long it keeps lines, so the ones kept forever stand out.