INSIGHTS
Why did our Azure bill go up? A 30-minute diagnosis
A step-by-step Cost Analysis procedure to find what drove an Azure bill increase: rule out billing effects, then trace service, day, resource, meter and owner.
Patrick Rezende
·
An Azure bill usually goes up for one of a handful of reasons: a new or resized resource, a service whose usage grew (logs, storage, data transfer), a commitment discount that expired, or a billing effect that involves no usage at all. Cost Analysis in Microsoft Cost Management can tell you which one in about 30 minutes, if you look in the right order.
The order matters more than the tool. Most people open Cost Analysis, stare at the accumulated cost chart, and start clicking on whatever is biggest. The biggest service is often not the one that changed. What follows is the sequence we use: rule out billing effects, then narrow from service to day to resource to meter to person.
Is it a usage increase or a billing effect? (minutes 0 to 5)
Some increases are caused by nobody. Check these first, because each one takes a minute and each one can send an engineer on a two-day hunt for a change that never happened.
Effect | What is going on | How to confirm |
|---|---|---|
Reservation or savings plan purchase | Actual cost shows the purchase in the month it was billed | Switch the view from Actual cost to Amortized cost. If the jump flattens, it was a purchase |
Credits ran out | Cost Management excludes credits, so it never showed them. The invoice did | Compare the "Azure credits applied" line on the two invoices |
Longer month | A resource running all month costs about 3.3% more in a 31-day month than a 30-day one, and about 10.7% more in March than in February | Compare average daily cost, not monthly totals |
Exchange rate | Under a Microsoft Customer Agreement billed in another currency, cost is calculated in US dollars and converted at a rate set once a month | Compare the two months in USD |
Billing period vs calendar month | Pay-as-you-go invoices follow a billing cycle that can run, for example, from the 8th to the 7th | Use the billing period date ranges in Cost Analysis, not "Last month" |
Open month | Costs are estimates until the invoice is generated, and estimates for tiered services use the highest tier price | Wait for the month to close before comparing |
Two timing rules from Microsoft's documentation explain most of the "the numbers changed since yesterday" confusion. Cost data for Enterprise Agreement and Microsoft Customer Agreement subscriptions typically lands within 8 to 24 hours, and pay-as-you-go can take up to 72 hours. A billing period is closed up to 72 hours after it ends, and charges can still change until the fifth day. If someone asks on the 2nd why last month went up, the honest answer is that last month is not finished yet.
If none of the above explains the gap, it is a real usage or price change. Move on.
Step 1: Pick the scope and measure the change (minutes 5 to 10)
Open Cost Management, select Cost Analysis, and set the scope. Use the subscription if one subscription holds most of the spend, because anomaly insights only appear at subscription scope. Use the management group or billing account if spend is spread across many.
Open the Cost by service view, which Microsoft provides for month-over-month comparison. Set the date range to the last six months, granularity to Monthly, and the chart to Column (stacked). Write down two things:
The size of the increase in dollars and percent, measured on closed months.
The shape. A step (flat, then one higher month, then flat at the new level) points to a change event: a deployment, a resize, an expiry. A slope (higher every month) points to accumulation: log volume, storage, backups, traffic growth.
Do this with Actual cost first, then switch to Amortized cost and check that the shape holds. If it only appears in one of the two, go back to the table above.
Step 2: Find the service that moved (minutes 10 to 15)
Keep monthly granularity, set Group by to Service name if it is not already, and switch the chart to Table. Compare the last two closed months and sort by the difference. In most tenants one or two services carry most of the increase, and the rest is noise.
Then change Group by to Resource group name. This tells you whether the increase sits in one team's area or is spread thin. Microsoft describes three kinds of change to look for: new costs that start from zero, removed costs that drop to zero, and changed costs on something that already existed. A resource group that did not exist two months ago is a new cost, and usually the fastest conversation you will have this week.
Cost Analysis cannot group by two attributes at once. The workaround is to filter on one and group by the other: filter to the service, group by resource group.
Step 3: Find the day it started (minutes 15 to 20)
Click the segment of the service or resource group that grew. That applies it as a filter. Now set granularity to Daily and the date range to cover both months. Daily granularity is limited to 92 days, which is enough.
You are looking for one of three patterns:
A clean step on a specific date. Something changed that day. Note that a change made mid-day takes two days to show its full effect, because the first day only carries part of it.
A weekly saw-tooth that got taller. Batch jobs, scheduled environments or weekday traffic grew.
A steady ramp. Something is accumulating and will keep growing next month if nobody acts.
The date is the most useful single fact you will get from this exercise. It turns "the bill went up" into "something changed on the 14th", which is a question an engineering team can answer.
Step 4: Find the resource and the meter (minutes 20 to 25)
With the filter still on, set Group by to Resource and narrow the date range to a few days either side of the change. The resource that moved will stand out. Select it, which filters to that one resource, and set Group by to Meter.
The meter tells you what kind of change it was:
The same meter, more quantity. Usage grew: more hours, more GB ingested, more transactions, more data transferred out.
One meter stops and a more expensive one starts on the same resource. Someone changed the SKU or tier. Microsoft's own walkthrough of this procedure ends on exactly this case: a VPN gateway whose VpnGw1 meter stopped on one day and whose VpnGw3 meter started the same day.
The same meter and quantity, a higher price. A discount stopped applying. The usual cause is a reservation that expired without renewal. Microsoft's documentation is plain about it: after expiry, usage is charged at pay-as-you-go rates. Add a filter on Pricing model and compare how much of the meter was covered before and after.
The Resources smart view also includes deleted resources, so a resource that ran for two weeks and was then deleted still shows up with its cost.
Step 5: Find who changed it (minutes 25 to 30)
You now have a resource, a date and a type of change. Azure Resource Graph records changes to resources in the resourcechanges table, including who made them and from which client. Open Resource Graph Explorer in the portal and run this, with your resource group name:
changedBy is a person's email or an application ID. If it is an application ID, it is probably your CI/CD pipeline, and the commit history for that day will tell you the rest. A value of System means a platform change that no user triggered. If the query returns nothing useful, the resource's Activity log and its owner tag are the next places to look.
Then ask the person. In our experience the answer is almost always reasonable: an incident, a load test, a customer onboarding, a migration. What usually goes wrong is the follow-up: nobody went back afterwards to scale it down or delete it.
The usual culprits in mid-market tenants
These are the patterns we find most often when a company of a few hundred people asks why the bill moved. They are patterns, not rules, and the meter from Step 4 tells you which one you have.
Culprit | How it shows up in Cost Analysis | The question to ask the owner |
|---|---|---|
Proof of concept or test environment left running | A resource group that starts from zero | Is anyone still using this, and who decides? |
Resize during an incident, never reverted | One meter stops, a pricier one starts, same resource | Is the incident over? |
Log ingestion growth | Log Analytics on a slope, same meters, more GB | Which tables grew, and did someone turn on verbose logging? |
Expired reservation | Same quantity, higher cost, pricing model back to on-demand | Was auto-renew off, and is the workload staying? |
Scale-out that never scaled back | Same compute meters, more hours | Did traffic grow by the same proportion? |
Snapshots and backups accumulating | Storage or backup on a slow, steady slope | What is the retention policy, and who set it? |
New data transfer path | Bandwidth charges up from a new replication or export job | Does this data need to cross regions or leave Azure? |
VMs that are "off" but still billed | Compute hours continue on machines the team believes are stopped | Were they deallocated or only stopped? |
The last one deserves its own explanation, and we wrote one: why stopped Azure VMs keep billing. For the expired reservation case, deciding between reservations and savings plans covers what to buy back.
Doing the same diagnosis from a cost export
The portal is fine for one investigation. If you have many subscriptions, or want to run this every month, export the data instead. Cost Management can export cost and usage details daily to a storage account, including in the FOCUS format, which combines actual and amortized cost in one dataset. Once the FOCUS export is loaded into Azure Data Explorer or Microsoft Fabric as a table (here called Costs), this query returns the 20 resources whose cost grew most between the last two calendar months:
EffectiveCost is the amortized figure, so reservation purchases do not show up as spikes. Replace it with BilledCost when you need the numbers that match what gets invoiced. Run it after the fifth of the month, when the prior month has settled.
What to do with the answer
Write one line per driver: the amount, the cause, the owner, and the decision (keep it, fix it, or revert it). Three or four lines usually explain the whole increase. Anything you cannot explain goes back through Step 4.
Then shorten the time to the next answer. Create an anomaly alert on each production subscription (Cost Management, Cost alerts, Add, alert type Anomaly). Microsoft's anomaly detection compares each day with a forecast built from the previous 60 days and runs 36 hours after the day ends in UTC, so you hear about a step change in about two days instead of at month end. Azure Advisor will not do this for you, for reasons we covered in what Azure Advisor does not do.
At Fidelis Solutions, this month-over-month delta by resource and meter is the first thing we look at in a new tenant, before any optimization work. If you want a quick read on where your own practice stands first, the free FinOps Score takes ten questions and no tenant access.
Frequently asked questions
Why is my Azure invoice higher than what Cost Management shows?
Cost Management leaves out taxes, support charges and credits. Credits are applied when the invoice is generated, so if a credit ran out, the invoice rises while Cost Analysis stays flat. During an open month, Cost Management also shows estimates that can change until the invoice is issued. Compare the invoice lines for credits and tax before you look for a usage change.
How long does it take for Azure costs to appear in Cost Analysis?
For Enterprise Agreement and Microsoft Customer Agreement subscriptions, cost data typically arrives within 8 to 24 hours. Pay-as-you-go subscriptions can take up to 72 hours. Microsoft closes a billing period up to 72 hours after it ends, and charges can still change until the fifth day. Do not diagnose last month on the first of the month.
Can buying a reservation make our Azure bill go up?
Yes, in the month you pay for it. Actual cost shows a reservation or savings plan purchase as a charge in the month it is billed. Switch Cost Analysis to Amortized cost and the purchase is spread daily across the term and assigned to the resources that used it. If the jump disappears in amortized view, it was a purchase, not new usage.
How do I find out who made the change that increased Azure costs?
Query the resourcechanges table in Azure Resource Graph Explorer for the resource group or resource you identified. Each change record includes changedBy (a user or application ID), clientType (for example Azure Portal) and the properties that changed. The Activity log for the resource and its owner tag are the other two places to look.
Sources
See where your Azure money is leaking.
Start with the free Score: ten questions, no tenant access. Or go straight to the 20-minute call.