Worked Example · Azure

Tracing an Azure Cost Overrun — A Worked Example

A bill that grew 3.4x in five months, broken down line by line — what was actually driving it, the four fixes that recovered most of it, and the one that mattered but saved nothing.

This is an illustrative example. The figures are composed to show the method, not drawn from a named engagement.

A team migrates a web application and its database to Azure. The estimate was £4,200 a month. Five months later the bill is £14,300, and nobody can say why.

The investigation took an afternoon, because the tagging was in place. Without it, this would have been a week of archaeology.

The breakdown#

Cost by service, current month:

ServiceMonthlyShare
App Service plans£3,91027%
SQL Database£3,48024%
Log Analytics ingestion£2,65019%
Bandwidth / egress£1,72012%
Storage£1,1408%
Application Gateway£7805%
Everything else£6204%
Total£14,300

Two of the top three were not in the estimate at all.

Finding 1 — non-production at production size (£2,840/month)#

Filtering by the environment tag:

EnvironmentMonthly
prod£8,190
staging£2,410
dev£1,860
untagged£1,840

Staging and dev ran the same App Service tier and database tier as production, 168 hours a week, for an eight-person team using them roughly 40.

Fix: scaled non-production down two tiers and scheduled a nightly stop with a morning start. Recovered: £2,840/month. One afternoon of work.

Finding 2 — log ingestion nobody chose (£2,650/month)#

Log Analytics was the third-largest line and nothing in the estimate mentioned it.

During migration, diagnostic settings were enabled at verbose level on every resource to help debug the cutover, with 90-day retention. The cutover finished in March; the setting stayed on.

Fix: dropped verbose to the level actually needed, retention to 30 days for non-production. Recovered: £1,980/month.

🔴 This is the most commonly missed line in a cloud bill. It appears during an incident or a migration, when nobody is watching cost, and then it never gets turned back down.

Finding 3 — the untagged £1,840#

Resources with no environment tag turned out to be:

  • A database restored to investigate a data question in April, never deleted (£620)
  • Two App Service plans from a proof of concept that was rejected (£410)
  • Unattached managed disks from resized virtual machines (£290)
  • A second Application Gateway from a test that was never removed (£520)

Nobody owned any of it, which is exactly why it survived five months.

Fix: deleted after confirming with the teams. Recovered: £1,840/month. A policy now denies resource creation without owner and environment tags.

Finding 4 — cross-zone egress (£1,720/month)#

The application and the database ended up in different availability zones after a resilience change in month three. Every query crossed a zone boundary, and that traffic is billed.

The resilience improvement was real and worth keeping. The cost was not understood at the time.

Fix: co-located the application tier with the database primary, keeping the standby in the second zone. Recovered: £1,190/month, resilience unchanged.

Where it landed#

Monthly
Before£14,300
After the four fixes£6,490
Original estimate£4,200

Still 55% above estimate — and the remaining gap was legitimate: real traffic was higher than forecast, and the resilience change added genuine cost. That is a much better conversation to have than "the bill tripled".

The fix that saved nothing and mattered most#

A budget alert at £5,000 with a second at £8,000, routed to a shared inbox someone reads.

It recovers no money. It means the next drift is noticed in week one rather than month five — and every finding above had been accumulating for months while the monthly total was seen by nobody with the authority to ask about it.

What transfers#

Tag from the first resource. Every finding here was found by filtering on a tag. The untagged £1,840 took longest precisely because it could not be filtered.

Look for the lines that were not in the estimate. Log ingestion and egress are the two that routinely appear afterwards and are rarely forecast.

Check what was turned up during an incident or migration. Verbose logging, larger tiers and extra instances get enabled under pressure and stay.

Alert on the total, not just the components. Nobody was looking at one number until somebody complained.

See Azure and the landing zone checklist, whose cost section exists because of estates shaped like this one.

Back to Azure