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

  1. 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.
  2. 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-Hours start with a short region code (USE2 is 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.
  3. 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 -15

The 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 text

Public 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 text

Disks left behind when a server was deleted:

aws ec2 describe-volumes --filters Name=status,Values=available \
  --query 'Volumes[].[VolumeId, Size, VolumeType, CreateTime]' --output text

Old snapshots, often from a backup job nobody remembers setting up:

aws ec2 describe-snapshots --owner-ids self \
  --query 'Snapshots[].[SnapshotId, VolumeSize, StartTime]' --output text

Databases 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 text

Logs 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 text

and this keeps 30 days of one of them:

aws logs put-retention-policy --log-group-name /aws/lambda/my-function --retention-in-days 30

Something 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.

See your whole AWS account in one calm view

Cloud GUI shows your files and functions from every region at once, in plain English, with what's failing up front. It connects with a read-only role you create and can delete any time. Free for one AWS account.

More guides

Free tool
IAM policy explainer

Paste an IAM policy and read it in plain English, with the risky parts flagged. It runs in your browser; nothing is sent anywhere.