2026-03-29 · Azure Cost
Why Did My Azure Bill Spike This Month?
Azure billing can be hard to reason about. The service names are verbose, the pricing model varies across services, and the Cost Management portal layers its own abstractions on top of the raw data. When your bill goes up unexpectedly, knowing where to start saves a lot of time.
Here are the most common reasons Azure bills spike, how to check each one, and how to fix it.
1. A Reservation or Azure Savings Plan Expired
Azure Reservations give you discounted pricing in exchange for a one- or three-year commitment. When a reservation expires, the underlying resources immediately fall back to pay-as-you-go rates with no warning and no email.
The gap is large. A Standard_D8s_v5 running in East US costs roughly $0.384/hr on pay-as-you-go. The equivalent one-year reserved rate is around $0.206/hr, about 46 percent less. A cluster of eight of those under an expired reservation adds roughly $1,300 per month to your bill starting the day it lapses.
**How to check:** Go to Cost Management > Cost Analysis. Set the view to Cost by Resource and add a filter for Pricing Model = On Demand. Compare this month against last. If you see resources that were previously discounted now showing at on-demand rates, a reservation expired. Also check the Reservations blade (search "Reservations" in the portal), it shows all active commitments with expiration dates.
**How to fix:** Purchase new reservations or an Azure Savings Plan to cover the affected resources. If you need flexibility on instance size or region, a Compute Savings Plan covers more scenarios than a single-SKU reservation. If the workload is short-lived, evaluate whether on-demand is acceptable until you decide.
2. VMSS or App Service Autoscaling Left Instances Running
Azure Virtual Machine Scale Sets and App Service plans scale out automatically under load. If a traffic event or a test triggered a scale-out and the scale-in rule did not fire cleanly, you can end up paying for significantly more compute than you need indefinitely.
VMSS instances are particularly easy to miss. Unlike Azure Functions or Container Apps that scale to zero, VMSS instances keep running until explicitly stopped or the scale-in threshold is crossed. An instance that would normally cost $150/month left running in an over-provisioned pool for a full billing period is a straightforward but avoidable charge.
**How to check:** Go to the VMSS resource in the portal and look at the Instances blade. Check the instance count over the past 30 days in the Scaling section. Compare the maximum instance count against what your normal traffic would require. Also check App Service Plans and look at the scale history in the Activity Log.
**How to fix:** Review and tighten your scale-in rules. Set a maximum instance cap below the level that would produce a budget surprise. For non-production environments, configure a scheduled scale-down at the end of the business day.
3. Blob Storage Operations or Egress Charges Spiked
Storage costs in Azure have two components that are easy to confuse. Blob storage charges per GB stored, but it also charges per 10,000 operations, separately for writes (Class 2) and reads (Class 1). The operation rates vary by tier: LRS Hot storage charges $0.0052 per 10,000 write operations and $0.0004 per 10,000 read operations. Those numbers sound small, but a data pipeline making millions of API calls generates real charges fast.
Egress works the same as other clouds. Traffic leaving Azure to the internet is billed per GB ($0.087/GB for the first 10 TB out of East US). Cross-region traffic within Azure is also billed. A new integration or CDN configuration that routes data differently than before can cause egress to jump without any new resources being created.
**How to check:** Go to the storage account in the portal and open Monitoring > Metrics. Add the Transactions metric and group by API Name to see which operations increased. For egress, add the Egress metric and compare week-over-week. In Cost Management, filter by Service = Storage and group by Meter to separate capacity charges from operations and egress charges.
**How to fix:** For operations, check whether your pipeline is making unnecessary LIST or GET calls. Batching small writes reduces operation counts. For egress, verify that data meant to stay within Azure is not routing out to the internet, and confirm CDN origins are pulling from within-region endpoints.
4. AKS Cluster Autoscaler Scaled Nodes Up and Did Not Scale Back
AKS node pools scale based on cluster autoscaler configuration. If a workload spike triggered additional nodes that were not scaled back afterward, or if the minimum node count was raised during a configuration change, you can end up with persistent excess compute charges.
The math compounds quickly. Each AKS node is a VM, billed at the standard Compute Engine rate for that size. Managed node pools also incur an OS disk charge per node, a 128 GB Premium SSD disk adds about $18/month per node. Scaling from 3 nodes to 12 nodes on a Standard_D4s_v5 node pool adds roughly $700/month in VM charges plus $162/month in disk charges.
**How to check:** Go to the AKS cluster in the portal and open Node Pools. Check the current node count for each pool against the minimum and maximum you configured. Also look at the cluster autoscaler profile settings, specifically the scale-down delay and the utilization threshold. A high scale-down delay (default is 10 minutes) means nodes can stay inflated long after load drops.
**How to fix:** Reduce the scale-down delay if your workloads tolerate it. Lower the minimum node count to the actual floor your base load requires. For dev or staging clusters, use node auto-provisioning or set a scheduled scale-down to minimize idle nodes overnight and on weekends.
5. Azure SQL Database or Elastic Pool Tier Changed
Azure SQL Database pricing is driven by the service tier and vCore count. The difference between tiers at the same vCore count is large. General Purpose costs about $0.124/vCore-hour. Business Critical costs about $0.494/vCore-hour, nearly four times as much, charged to cover the in-memory replica that Business Critical uses for high availability.
If a developer upgraded a database from General Purpose to Business Critical for a performance investigation and did not revert it, the cost impact is immediate and ongoing. At 8 vCores, the monthly difference between General Purpose and Business Critical is roughly $2,150.
Elastic pool configurations have a related trap. The pool capacity is billed regardless of how many databases are in it or how heavily they are being used. An 8-vCore Business Critical elastic pool running nearly idle still charges for the full 8 vCores.
**How to check:** Go to the SQL Database resource in the portal and open the Pricing Tier blade. Verify the current tier matches what was budgeted. For elastic pools, check the pool resource directly. In Cost Management, filter by Service = Azure SQL Database and group by Resource to see which database or pool increased.
**How to fix:** Change the pricing tier back to General Purpose if Business Critical was a temporary test change. For elastic pools, adjust the DTU or vCore allocation to match actual workload requirements. Most databases do not need Business Critical unless the workload specifically requires an in-memory replica.
6. An Untagged Resource Was Created and Nobody Noticed
The least dramatic but surprisingly common cause: someone created something new and it went unnoticed. A new Log Analytics workspace with heavy data ingestion. An Application Gateway left running after a test deployment. An ExpressRoute circuit provisioned for a proof-of-concept. An Azure Load Balancer that charges hourly even with no traffic flowing through it.
Without consistent tagging, new resources have no owner and no cost center. They show up in the total but are invisible in tag-based cost views.
**How to check:** In Cost Management, group the current month by Resource and sort by cost. Compare against the prior month. Any resource with non-zero cost this month and zero cost last month is new. Also run a query against your Azure Resource Graph: resources | where tags !contains 'owner' returns everything without an owner tag.
**How to fix:** Tag the resource and assign an owner immediately. If it was created for a test, evaluate whether it can be deleted. Enforce tagging through Azure Policy, a Deny policy on resource creation without required tags prevents the problem from recurring.
How to Find the Root Cause Step by Step
Start in Azure Cost Management. Open Cost Analysis, set the date range to cover both months, and switch the view to Cost by Service. Sort by the largest absolute increase. This gives you the service responsible.
Once you have the service, group by Meter within that service. The Meter field in Azure billing is equivalent to the usage type in AWS: it tells you exactly what category of charge drove the increase. If the service is Virtual Machines and the Meter is Standard D8s v5, you know it is a specific VM size running more hours than before.
From there, group by Resource to find the specific VM, database, storage account, or cluster responsible. That gives you an owner to contact and an action to take.
For the deepest investigation, export your Usage Details from Cost Management for both months and run the comparison yourself. The MeterName, ResourceName, Quantity, and UnitPrice columns let you split the cost delta into volume versus price components, the same decomposition that shows whether you need to reduce usage or buy a commitment.
How to Prevent Future Spikes
Set Azure Budgets with alerts at 80 percent and 100 percent of your expected monthly spend. Add a forecasted budget alert as well, it warns you mid-month when the trend is heading over budget before the billing period ends.
Track reservation and savings plan expirations on your team calendar at 60 and 30 days out. Azure does not send expiration reminders by default.
Enable Azure Cost Anomaly Alerts. These are separate from budget alerts and fire when a service's daily cost deviates significantly from its recent pattern, even if you have not hit a budget threshold.
Enforce resource tagging with Azure Policy. A Deny policy that blocks resource creation without required tags (environment, owner, team) means new resources always have an owner before they can generate charges.
Bottom Line
Most Azure bill spikes trace to one of three things: a reservation expired, something scaled up and was not scaled back, or a developer left a resource running. The hard part is finding which one quickly.
Cost Management gets you to the service. The Usage Details export gets you to the root cause. If you want to skip the manual work, BillSpike supports FOCUS exports from Azure today alongside AWS CUR files. The same volume versus price variance analysis runs on both.
Analyze your own AWS cost spike at billspike.io