Setting Up a Free Tier Billing Alarm in AWS CloudWatch (Email Alert at $5)

A Free Tier billing alarm in AWS CloudWatch is the fastest way to catch unexpected charges before a surprise invoice arrives at month-end.

TL;DR: Free Tier Billing Alarm Setup Steps

StepWhat to DoKey Requirement
1Enable billing alerts in Account PreferencesMust be done in us-east-1; one-time account setting
2Create an SNS topic and email subscriptionEmail must be confirmed before alarm can notify
3Create the CloudWatch billing alarm at $5 thresholdMetric only available in us-east-1
4Verify alarm state and confirm SNS subscriptionAlarm stays in INSUFFICIENT_DATA until billing data arrives

Why Free Tier Billing Alarms Exist — and Why Teams Skip Them

AWS Free Tier usage is not automatically capped. When a service exceeds its monthly free allowance, charges accrue silently. CloudWatch billing alarms monitor the EstimatedCharges metric published by AWS Billing and send a notification when a defined threshold is crossed. The alarm does not stop charges — it notifies you so you can act.

In practice, teams setting up a personal or sandbox account skip this step because the console makes it look optional. It is not optional if you care about your credit card.

Think of a billing alarm the way you think of a low-fuel warning light: it does not stop the car, but without it you will not know you are about to stall.

Architecture: How the Billing Alarm Signal Flows

graph LR Billing[AWS Billing Service] -->|Publishes EstimatedCharges| CW[CloudWatch us-east-1] CW -->|Evaluates threshold| Alarm[Billing Alarm] Alarm -->|State change ALARM| SNS[SNS Topic] SNS -->|Email notification| Inbox[Your Email Inbox]
  1. AWS Billing aggregates estimated charges across all services and publishes the EstimatedCharges metric to CloudWatch in the us-east-1 region.
  2. CloudWatch Alarm evaluates the metric against your $5 threshold. When the metric value exceeds the threshold, the alarm transitions to ALARM state.
  3. SNS Topic receives the state-change notification from CloudWatch.
  4. Email Subscription on the SNS topic delivers the alert to your inbox.

Step 1: Enable Billing Alerts in Account Preferences

Billing metric data is not published to CloudWatch by default. You must opt in once per AWS account. This setting is global but the metric itself is only available in us-east-1.

— Why this step: Without enabling billing alerts, the EstimatedCharges metric never appears in CloudWatch, and every subsequent step silently produces an alarm with no data.

Navigate to the AWS Billing console → Billing Preferences → check Receive Billing Alerts → save preferences. There is no CLI command to enable this setting; it must be done through the Billing console or via the Billing API. Confirm the setting is saved before proceeding.

Step 2: Create an SNS Topic and Email Subscription for the Free Tier Billing Alarm

CloudWatch alarms notify through Amazon SNS. You need a topic and a confirmed email subscription before the alarm can deliver notifications.

— Why this step: An alarm wired to an unconfirmed SNS subscription will transition to ALARM state correctly but deliver no email — a silent failure that defeats the entire purpose.

You are about to run two commands. The first creates the topic and returns its ARN. Copy that ARN — you need it in Step 3.

# Create the SNS topic (run in us-east-1)
aws sns create-topic \
  --name billing-alarm-topic \
  --region us-east-1
# Subscribe your email address to the topic
# Replace TOPIC_ARN with the ARN returned above
# Replace you@example.com with your actual address
aws sns subscribe \
  --topic-arn arn:aws:sns:us-east-1:123456789012:billing-alarm-topic \
  --protocol email \
  --notification-endpoint you@example.com \
  --region us-east-1

After running the subscribe command, AWS sends a confirmation email. Open it and click Confirm subscription. The subscription status must show Confirmed before the alarm will deliver notifications. You can verify status with:

aws sns list-subscriptions-by-topic \
  --topic-arn arn:aws:sns:us-east-1:123456789012:billing-alarm-topic \
  --region us-east-1

Look for "SubscriptionArn" containing a full ARN (not the string PendingConfirmation).

Step 3: Create the CloudWatch Billing Alarm at the $5 Threshold

With billing metrics enabled and SNS confirmed, you can now create the alarm. The EstimatedCharges metric lives in the AWS/Billing namespace and uses the dimension Currency=USD. This metric is only available in us-east-1 regardless of where your resources run.

— Why this step: The metric namespace, dimension name, and region are all fixed by AWS. Using any other region or omitting the Currency dimension results in a metric that returns no data, leaving the alarm permanently in INSUFFICIENT_DATA state.

The engineer's first instinct is often to create this alarm in whatever region their workload runs in. That will not work. Billing metrics are centralized in us-east-1 by design — region of resource deployment is irrelevant here.

aws cloudwatch put-metric-alarm \
  --alarm-name "FreeTierBillingAlarm" \
  --alarm-description "Alert when estimated charges exceed 5 USD" \
  --metric-name EstimatedCharges \
  --namespace AWS/Billing \
  --statistic Maximum \
  --dimensions Name=Currency,Value=USD \
  --period 86400 \
  --evaluation-periods 1 \
  --threshold 5 \
  --comparison-operator GreaterThanThreshold \
  --alarm-actions arn:aws:sns:us-east-1:123456789012:billing-alarm-topic \
  --treat-missing-data notBreaching \
  --region us-east-1

Key parameter decisions explained:

  • --statistic Maximum: Billing metrics represent cumulative estimated charges. Maximum captures the highest reported value within the period, which reflects the current running total.
  • --period 86400: AWS updates the EstimatedCharges metric several times per day. A 86400-second (24-hour) period is a common and practical evaluation window.
  • --treat-missing-data notBreaching: Prevents the alarm from firing during periods when no billing data has been published yet (common at the start of a billing cycle).

The threshold is a floating-point value. Setting it to 5 means the alarm triggers when estimated charges exceed $5.00 USD.

Step 4: Verify the Free Tier Billing Alarm State

After creation, the alarm will initially report INSUFFICIENT_DATA. This is expected — CloudWatch has not yet evaluated a full period of billing data. It is not an error.

— Why this step: Confusing INSUFFICIENT_DATA with a misconfiguration causes engineers to delete and recreate the alarm repeatedly, which does not resolve the state and wastes time.

aws cloudwatch describe-alarms \
  --alarm-names "FreeTierBillingAlarm" \
  --region us-east-1

In the output, check StateValue. Valid states are OK, ALARM, and INSUFFICIENT_DATA. Once AWS publishes billing data for the current period, the alarm will transition to OK (if charges are below $5) or ALARM (if they are not).

graph LR Start([Alarm Created]) --> ID[INSUFFICIENT_DATA] ID -->|First data point evaluated| OK[OK] ID -->|First data point over threshold| ALARM[ALARM] OK -->|Charges exceed 5 USD| ALARM ALARM -->|Charges drop to 5 USD or below| OK
  1. INSUFFICIENT_DATA: Initial state. No billing metric data point has been evaluated yet. Normal at alarm creation.
  2. OK: Billing metric evaluated; estimated charges are at or below $5.
  3. ALARM: Estimated charges exceeded $5. SNS notification has been sent.

The alarm does not auto-resolve charges. Once you receive the email, log in to the Billing console to identify which service is generating unexpected spend.

IAM Permissions Required

If you are running these CLI commands as an IAM user or role rather than the root account, the principal needs the following minimum permissions:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowSNSTopicManagement",
      "Effect": "Allow",
      "Action": [
        "sns:CreateTopic",
        "sns:Subscribe",
        "sns:ListSubscriptionsByTopic"
      ],
      "Resource": "arn:aws:sns:us-east-1:123456789012:billing-alarm-topic"
    },
    {
      "Sid": "AllowCloudWatchAlarmManagement",
      "Effect": "Allow",
      "Action": [
        "cloudwatch:PutMetricAlarm",
        "cloudwatch:DescribeAlarms"
      ],
      "Resource": "*"
    }
  ]
}

Note: cloudwatch:DescribeAlarms does not support resource-level restrictions and requires "Resource": "*". Enabling billing alerts in the Billing console requires the aws-portal:ModifyBilling permission or root account access, depending on your account configuration.

Common Mistakes That Break Free Tier Billing Alarms

The most frequent failure is creating the alarm in the wrong region. Because EstimatedCharges is only published in us-east-1, an alarm created in eu-west-1 or any other region will remain in INSUFFICIENT_DATA indefinitely with no error message.

The second failure mode is an unconfirmed SNS subscription. The alarm fires correctly, CloudWatch records the state transition, but no email arrives. Engineers then assume the alarm is broken and rebuild it — the subscription confirmation step is the actual fix.

Pricing and service quota limits vary — always check the AWS Free Tier page and the official CloudWatch billing alarm documentation for current details.

Glossary

EstimatedCharges
A CloudWatch metric in the AWS/Billing namespace representing the estimated total charges for your AWS account in the current billing period. Published in us-east-1 only.
SNS Topic
An Amazon Simple Notification Service endpoint that fans out messages to one or more subscribers. Used here to deliver email notifications from CloudWatch alarm state changes.
INSUFFICIENT_DATA
A CloudWatch alarm state indicating that not enough metric data has been collected to evaluate the alarm condition. Expected immediately after alarm creation.
treat-missing-data
A CloudWatch alarm parameter controlling how the alarm behaves when no data points exist for the evaluation period. notBreaching treats missing data as within threshold.
Billing Alerts (Preference)
An account-level opt-in setting in the AWS Billing console that enables publication of billing metrics to CloudWatch. Must be enabled before billing alarms can function.

Related Posts

Comments

Popular posts from this blog

EC2 No Internet Access in Custom VPC: Fix Internet Gateway and Route Table

EC2 SSH Connection Timeout: Which Security Group Rules to Check

Difference Between IAM User and IAM Role: Which One Should Your EC2 Use?