When Your AWS Bill Suddenly Jumps — the 10 Most Common Causes
You open the bill and it’s double last month’s. Traffic didn’t double, and you don’t remember adding instances. This post covers the order for finding the culprit, plus the ten causes that come up most often in practice. The basics of billing (alerts, Cost Explorer, the free tier) are covered in AWS Basics #3; here we focus on the “it suddenly jumped” scenario. Example prices are from us-east-1 and vary by region.
Find the culprit first #
Before walking the list of causes, you can narrow down which service grew in about thirty seconds.
- In Cost Explorer, set the range to “last 3 months, daily” and group by Service. Which service jumped, and when, shows up straight away on the graph.
- Once you have the service, switch the same view to group by Usage Type. The same “EC2” line splits here into instance hours, EBS, or data transfer.
- Going down to individual resources requires tags. If tagging isn’t in place, take this incident as the reason to set up cost allocation tags.
With the area narrowed, find your case below.
1. NAT Gateway data processing #
The undisputed number one. On top of the hourly charge (about $0.045), a NAT Gateway bills per gigabyte that passes through it (about $0.045/GB). If workloads in private subnets exchange bulk traffic with AWS services like S3 and ECR through the NAT, the bill climbs with every container image pull and data pipeline run.
- Confirm: check whether
NatGateway-Bytesspiked under Usage Type. - Fix: route S3 and DynamoDB through gateway VPC endpoints (free), and other services like ECR through interface endpoints, bypassing the NAT. One gateway endpoint shaving hundreds of dollars off the monthly bill is a common story.
2. CloudWatch Logs ingestion #
With logs, ingestion costs more than storage (about $0.50/GB). Debug logging left on after a deploy, or a repeating error spewing stack traces, can push log ingestion past your compute bill.
- Confirm:
DataProcessing-Bytesunder Usage Type, and theIncomingBytesmetric per log group. - Fix: adjust log levels and fix the repeating error first. While you’re there, clean up log groups whose retention is set to “never expire” — that’s the default.
3. EBS snapshots and AMIs piling up #
Automated backups producing snapshots with no deletion policy. Snapshots are incremental, so each looks small, but hundreds of them together outgrow the source volume. Snapshots created alongside an AMI are not deleted automatically when you deregister the AMI.
- Confirm: the
EBS:SnapshotUsagetrend under Usage Type. - Fix: set retention counts and periods with Data Lifecycle Manager or AWS Backup. Start the cleanup with orphaned snapshots whose source volumes are gone.
4. Charges that outlive stopped resources #
Stopping an EC2 instance doesn’t stop the attached EBS volumes or the allocated public IPv4 addresses from billing. Public IPv4 in particular has cost about $0.005/hour per address (about $3.6/month) since 2024, used or not — a few dozen unattached Elastic IPs run into three figures on their own.
- Confirm:
PublicIPv4:InUseAddressandIdleAddressunder Usage Type; volumes in theavailablestate. - Fix: release unattached EIPs, snapshot-then-delete orphaned volumes, and for instances that will stay stopped for long, bake an AMI and terminate.
5. Data transfer — cross-region, cross-AZ, internet out #
Everyone remembers internet egress (about $0.09/GB), but cross-region replication and cross-AZ traffic (around $0.01/GB each way) accumulate too. The classic cases are a multi-AZ setup where the application and database chat across AZs, and cross-region replication someone enabled.
- Confirm:
DataTransfer-Regional-Bytes(cross-AZ, intra-region) andDataTransfer-Out-Bytesunder Usage Type. - Fix: co-locate in one AZ (weigh the availability trade-off), absorb egress with CloudFront, and re-examine the replication scope.
6. Lambda runaways and recursion #
A Lambda writes to an S3 bucket, and the write event triggers the same Lambda — the classic recursive loop. Retry storms without throttling (SQS redrives, event reprocessing) produce the same shape of bill.
- Confirm: the
Invocationsmetric over time, looking for one function exploding. - Fix: break the loop with event filters (AWS’s recursive-loop detection stops some of these automatically), set DLQs and maximum retries, and cap concurrency.
7. S3 request charges and version buildup #
S3 bills for request counts, not just storage (PUT and LIST cost more than GET). Typical culprits are batch jobs repeatedly listing millions of small objects, and versioned buckets overwritten continuously with no lifecycle rule. Old versions don’t show in the console view, but every one of them bills.
- Confirm:
Requests-Tier1/2under Usage Type, and per-version storage in S3 Storage Lens. - Fix: expire noncurrent versions with lifecycle rules, bundle small objects, and minimize LIST calls.
8. Dev environments running 24/7, and overprovisioning #
Dev and staging instances running nights and weekends, and RDS instances sized “big, just in case,” push the baseline steadily upward. This appears as a creep rather than a spike, or as a step in the month a new environment was created.
- Confirm: group costs by environment tag; check Compute Optimizer’s downsizing recommendations.
- Fix: scheduled stops for dev environments (Instance Scheduler) and recommendation-driven downsizing.
9. RI and Savings Plans expiration #
If usage is flat but the bill jumped, suspect this first. When Reserved Instances or Savings Plans expire, the same usage starts billing at on-demand rates — a 30–40% increase with nothing changed.
- Confirm: expiration dates and coverage drops in the RI/SP coverage reports in the Billing console.
- Fix: set expiration alerts in advance, then renew or re-commit to match current usage. The pricing models are covered in SAA Domain 4-1.
10. CloudWatch metrics and API calls — monitoring tools polling #
An external monitoring tool (or your own dashboard) polling GetMetricData at high frequency turns CloudWatch API charges into a visible line item. So do custom metrics (about $0.30/month each) created at high cardinality — per instance, per customer.
- Confirm:
CW:GMD-Metrics(GetMetricData) andCW:MetricMonitorUsage(custom metrics) under Usage Type. - Fix: relax polling intervals, collect only the metrics you use, and reduce cardinality.
Prevention — hear about the next spike before the bill #
Once the culprit is fixed, turn on three things so the next one doesn’t arrive via invoice.
- AWS Budgets — set a monthly budget with forecast-overrun alerts. The minimum safety net.
- Cost Anomaly Detection — alerts when a service departs from its usual pattern. It’s free, and it catches most of the cases in this post within days.
- Cost allocation tags and a regular review — untagged costs can’t be traced. Make a monthly Cost Explorer review a team routine.
The operational flow, dashboards included, is covered in AWS Practice #6.
Summary #
- Hunting starts in Cost Explorer, grouping by Service and then Usage Type. The graph answers, not intuition.
- The regulars behind spikes: NAT Gateway processing, CloudWatch Logs ingestion, snapshot accumulation, data transfer, Lambda runaways.
- Flat usage with a higher bill points to RI/Savings Plans expiration first.
- Items that bill without being used — public IPv4, EBS on stopped instances — need a periodic cleanup list.
- With Budgets and Cost Anomaly Detection on, the next spike arrives as an alert, not an invoice.