Nurture TechnologiesNurture Tech
DevOps16 min·July 24, 2026

AWS Bill Doubled OvernightComplete Diagnosis Guide

AWS Cost ExplorerAWS CLIEC2RDSNAT GatewayS3CloudWatch

You open the AWS billing console and the current month's bill is already double last month's total. Use Cost Explorer, AWS CLI queries, and service-specific checks to pinpoint the source within 30 minutes.

Problem Summary

An unexpected spike in AWS spend is one of the most stressful infrastructure events because it combines financial urgency with technical ambiguity. The bill has already accrued; every minute of continued diagnosis is costing money. This guide gives you a structured 30-minute investigation path using Cost Explorer, the AWS CLI, and service-specific consoles to isolate the charge source and take immediate corrective action.

Symptoms

  • AWS Cost Explorer shows a sharp vertical jump in spend starting at a specific date and time
  • Month-to-date charges are already at or above last month's total bill
  • A billing alert email arrived from AWS (if you had budget alerts configured)
  • One specific AWS service dominates the unexpected increase in the Cost Explorer breakdown
  • Usage metrics do not correlate with the cost increase traffic is normal but spend is not
  • New line items appear in the bill that were not present in previous months
  • Data transfer or NAT Gateway line items are significantly larger than historical norms
  • No new production deployments happened, yet costs increased

Business Impact

A doubled AWS bill represents an immediate financial impact. For startups on tight budgets, an unexpected $5,000-$50,000 charge can threaten runway. Beyond the immediate cost, unchecked AWS spend often indicates a systemic architecture problem data being transferred unnecessarily, resources left running from past experiments, or an autoscaling policy that has no upper bound. Fixing the symptom without fixing the root cause means the spike will recur.

Root Cause

The most common root causes in order of frequency: NAT Gateway data processing charges from application-level logging or S3 traffic routed through NAT instead of a VPC endpoint, forgotten EC2 or RDS instances left running from development experiments, S3 cross-region replication or data transfer out to internet costs, unexpected autoscaling event that launched large instance types, CloudWatch log ingestion from verbose application logging, and Elastic IPs that are allocated but not attached to a running instance (charged at $0.005/hr when unattached).

NAT Gateway charges are the single most surprising AWS cost for engineering teams. NAT Gateway costs $0.045 per GB of data processed if your EC2 instances are sending application logs to CloudWatch or pulling Docker images from ECR through a NAT Gateway, this adds up extremely fast.

Diagnosis

Step 1 Use Cost Explorer to Identify the Service and Time

Open AWS Console → Cost Management → Cost Explorer. Set the time range to the last 30 days, group by Service, and identify which service shows the spike. Then drill down by filtering to that service and grouping by Usage Type to find the specific charge category.

$aws ce get-cost-and-usage --time-period Start=2026-07-01,End=2026-07-24 --granularity DAILY --metrics BlendedCost --group-by Type=DIMENSION,Key=SERVICE --output table
$aws ce get-cost-and-usage --time-period Start=2026-07-20,End=2026-07-24 --granularity HOURLY --metrics BlendedCost --group-by Type=DIMENSION,Key=USAGE_TYPE --filter '{"Dimensions":{"Key":"SERVICE","Values":["Amazon EC2"]}}' --output table

Step 2 Check for Forgotten Running Instances

Scan all regions for running EC2 instances and RDS databases. Engineers frequently launch instances in non-default regions for experiments and forget them. Use the CLI to check every region.

find-all-instances.sh
#!/bin/bash
# List all running EC2 instances across every region
for region in $(aws ec2 describe-regions --query 'Regions[*].RegionName' --output text); do
  instances=$(aws ec2 describe-instances     --region "$region"     --filters Name=instance-state-name,Values=running     --query 'Reservations[*].Instances[*].[InstanceId,InstanceType,LaunchTime,Tags[?Key==`Name`].Value|[0]]'     --output text 2>/dev/null)
  if [ -n "$instances" ]; then
    echo "=== Region: $region ==="
    echo "$instances"
  fi
done
$aws rds describe-db-instances --query 'DBInstances[*].[DBInstanceIdentifier,DBInstanceClass,DBInstanceStatus,MultiAZ,StorageAllocated]' --output table

Step 3 Investigate NAT Gateway Data Transfer

If NAT Gateway is the top charge, the fix is usually routing S3 and DynamoDB traffic through VPC Gateway Endpoints (free) instead of NAT Gateway. First, measure your NAT Gateway throughput to confirm the scale.

$aws cloudwatch get-metric-statistics --namespace AWS/NATGateway --metric-name BytesOutToDestination --dimensions Name=NatGatewayId,Value=<NAT_GW_ID> --start-time 2026-07-20T00:00:00Z --end-time 2026-07-24T00:00:00Z --period 3600 --statistics Sum --output table

Create a VPC Gateway Endpoint for S3 in your VPC (free, takes 2 minutes). Traffic from EC2 instances to S3 in the same region then bypasses NAT Gateway entirely. For ECR, use VPC Interface Endpoints. Together these often reduce NAT Gateway costs by 60-80%.

Step 4 Find Unattached Elastic IPs and Unused Resources

Elastic IPs cost $0.005/hr when not attached to a running instance. Small individually, but teams accumulate dozens. Also check for unattached EBS volumes, which accrue storage charges indefinitely.

$aws ec2 describe-addresses --query 'Addresses[?AssociationId==null].[PublicIp,AllocationId,Domain]' --output table
$aws ec2 describe-volumes --filters Name=status,Values=available --query 'Volumes[*].[VolumeId,Size,VolumeType,CreateTime]' --output table

Step 5 Audit CloudWatch Log Ingestion and S3 Request Costs

CloudWatch log ingestion costs $0.50/GB. Verbose DEBUG logging in production can ingest hundreds of GB per day. Check log ingestion rates and set log group retention policies.

$aws logs describe-log-groups --query 'logGroups[*].[logGroupName,storedBytes,retentionInDays]' --output table | sort -k2 -rn | head -20
set-log-retention.sh
#!/bin/bash
# Set 14-day retention on all log groups that have no retention policy
aws logs describe-log-groups --query 'logGroups[?retentionInDays==`null`].logGroupName' --output text |   tr '\t' '\n' |   while read group; do
    echo "Setting 14-day retention on: $group"
    aws logs put-retention-policy --log-group-name "$group" --retention-in-days 14
  done

Production Failure Scenarios

Scenario 1 Autoscaling Launched GPU Instances

An autoscaling group was configured with p3.2xlarge instances as the scale-out type for a traffic spike. The spike occurred, 20 instances launched, traffic subsided but the scale-in policy had a 2-hour cooldown. At $3.06/hr per instance that is $1,224 for a 20-instance-hour burst. Check autoscaling activity: aws autoscaling describe-scaling-activities --auto-scaling-group-name <name>

Scenario 2 S3 Cross-Region Replication Enabled Accidentally

Someone enabled cross-region replication on a bucket with 10 TB of data. Replication transfer costs $0.02/GB. The initial sync cost $200 and will continue to cost for every new object. Check bucket replication config: aws s3api get-bucket-replication --bucket <bucket-name>

Scenario 3 RDS Reserved Instance Expired

A 1-year RDS Reserved Instance expired last month. The instance silently fell back to on-demand pricing, which is 3-4x more expensive. There is no notification when Reserved Instances expire. Check reservation status in the RDS console under Reserved Instances, or: aws rds describe-reserved-db-instances

Prevention Checklist

  • Set up AWS Budgets alerts at 50%, 80%, and 100% of expected monthly spend
  • Enable AWS Cost Anomaly Detection it uses ML to detect unusual spending patterns and sends daily/weekly alerts
  • Create VPC Gateway Endpoints for S3 and DynamoDB in every VPC to eliminate unnecessary NAT Gateway charges
  • Tag all resources with Environment, Team, and Project tags untagged resources are invisible in cost analysis
  • Use AWS Trusted Advisor to get a monthly report of idle instances, unattached EIPs, and underutilized resources
  • Set a maximum capacity on every autoscaling group never leave max-capacity as unlimited
  • Set log retention policies on all CloudWatch log groups 30 days for production, 7 days for dev/staging
  • Review Reserved Instance and Savings Plans expiry dates monthly and renew 30 days before expiry
  • Run a monthly 'resource cleanup' ritual: delete snapshots older than 90 days, release unattached EIPs, delete available EBS volumes
  • Enable S3 Intelligent-Tiering or lifecycle policies on buckets older than 30 days

Resolution Summary

Start with Cost Explorer to identify the service and time of the spike within 5 minutes. Then follow the service-specific diagnosis: for NAT Gateway, add VPC endpoints; for EC2/RDS, terminate forgotten instances; for S3, check for new replication or large transfer-out events; for CloudWatch, cap log ingestion with retention policies. Most bill doublings have a single dominant cause that, once fixed, immediately stops the bleeding.

Lessons Learned

  • AWS billing alerts are the single highest-ROI infrastructure investment set them before you need them
  • NAT Gateway is the most commonly misunderstood AWS cost; every team should add VPC endpoints on day one
  • Reserved Instance and Savings Plans expirations are silent calendar reminders are non-negotiable
  • Resource tagging is a prerequisite for cost accountability without tags you cannot assign cost to a team or project
  • Autoscaling max-capacity limits prevent runaway costs; treat them as a financial safety circuit breaker

Conclusion

Unexpected AWS bill spikes are almost always preventable in retrospect. The investigation process described here Cost Explorer for service identification, CLI commands for resource enumeration, and service-specific metrics for confirmation can identify the root cause in under 30 minutes. Once you have found and fixed the immediate issue, implement the prevention checklist to build cost visibility into your operational baseline. A bill that doubled overnight is a symptom of missing observability, not just a cost problem.

Nurture Technologies

NEED HELP WITH YOUR STACK?

Nurture Technologies builds and maintains production-quality software for startups and businesses. If engineering problems are slowing you down, our team can help.

Talk to our team →
FAQ

FREQUENTLY ASKED QUESTIONS

How do I find which AWS service is causing the unexpected charges?+

Open Cost Explorer → set time range to last 30 days → group by Service. The service with the largest absolute increase is your starting point. Then filter to that service and group by Usage Type to find the specific charge category.

What is NAT Gateway data processing charge and how do I reduce it?+

NAT Gateway charges $0.045 per GB of data that flows through it in either direction. The fastest reduction is creating VPC Gateway Endpoints for S3 and DynamoDB (free), which routes traffic directly without going through NAT Gateway.

How do I scan all AWS regions for running instances I might have forgotten?+

Use the AWS CLI in a loop over all regions: aws ec2 describe-regions --query 'Regions[*].RegionName' --output text | xargs -I{} aws ec2 describe-instances --region {} --filters Name=instance-state-name,Values=running

Does AWS notify me when Reserved Instances expire?+

AWS sends a notification 30 days before expiry, but it goes to the account email address which teams often do not monitor closely. Set a calendar reminder and check the RDS/EC2 Reserved Instances dashboard monthly.

What is AWS Cost Anomaly Detection and how does it help?+

Cost Anomaly Detection is a free AWS service that uses ML to identify unusual spending patterns. It can alert you within hours of a spike starting, whereas budget alerts only fire when you cross a monthly threshold.

How much do unattached Elastic IPs cost?+

Unattached Elastic IPs cost $0.005 per hour, which is $3.60/month per IP. Individually small, but accounts accumulate dozens over time. Run aws ec2 describe-addresses --query 'Addresses[?AssociationId==null]' monthly to clean up.

Can I get a refund from AWS for unexpected charges caused by a misconfiguration?+

AWS does occasionally offer one-time courtesy credits for unexpected charges due to service anomalies or clear misconfiguration, but it is not guaranteed. Open a support case immediately with the specific cost data and a clear explanation of what happened.

What is the fastest way to stop an ongoing AWS cost spike?+

Once you identify the source: terminate forgotten instances (EC2 stop or terminate), delete unused EBS volumes, release unattached EIPs, reduce autoscaling max capacity, and add VPC endpoints. All of these take effect within minutes.

How do I set up AWS billing alerts?+

Go to AWS Billing → Budgets → Create Budget. Create a cost budget for your expected monthly amount and add alert thresholds at 50%, 80%, and 100%. Alternatively use CloudWatch billing alarm: aws cloudwatch put-metric-alarm with metric AWS/Billing EstimatedCharges.

How long does it take for AWS Cost Explorer to show recent charges?+

Cost Explorer data is typically 24 hours delayed. For near-real-time spend visibility during an incident, use the AWS Billing console's Cost and Usage Report (if configured with hourly granularity) or check service-specific CloudWatch metrics.