Skip to main content
emnode
Cost

Eliminate unprovisioned ExpressRoute circuits

An ExpressRoute circuit starts billing the moment its service key is issued, not when traffic flows. A circuit left in provider status 'Not provisioned' is a private connection you are paying for and not using: find every one that has sat unprovisioned for over a month and delete the ones nobody is going to light up.

12 min·10 sections·AZURE

Last reviewed

Unprovisioned ExpressRoute circuits: the basics

What does a circuit you are paying for but not using actually look like?

An ExpressRoute circuit is the Azure-side half of a private connection between your network and Microsoft. Creating one is a two-party handshake: you create the circuit resource in Azure, which issues a service key, and your connectivity provider then provisions their side against that key. Until the provider finishes, the circuit sits in provider status 'Not provisioned'. The catch is that Azure bills the circuit from the moment the service key is issued, not from the moment the provider lights it up or the first packet flows. A circuit that never gets provisioned is therefore a private connection you are paying for and not using.

Azure Advisor turns this into a specific cost recommendation: 'Reduce costs by eliminating unprovisioned ExpressRoute circuits'. It flags any circuit that has been in provider status 'Not provisioned' for more than one month and recommends deleting it if you are not planning to provision it with your connectivity provider. The signal is deliberately conservative: a month is long enough that a circuit stuck unprovisioned is almost never a provisioning still in flight and almost always an abandoned plan, a cancelled migration, or a test someone forgot to tear down.

Most of this spend is drift, not intent. A circuit spun up for a datacentre migration that slipped, a proof of concept that proved the point and moved on, a provider order that fell through, a circuit recreated in a different region while the original was left behind. Each one keeps billing at its monthly port charge for as long as the resource exists in Azure. The work is to find every circuit sitting unprovisioned past the one-month mark, confirm which are genuinely waiting on a live provider order, and delete the rest to stop the meter.

In this lesson you will learn why an ExpressRoute circuit bills from the moment its service key is issued rather than from first traffic, how Azure Advisor identifies circuits stuck unprovisioned past the one-month mark, and how to confirm which are abandoned and delete them safely without disturbing the provisioning that is genuinely still in flight. The Keep learning section links the Advisor cost reference and the ExpressRoute workflow and billing documentation.

Fun fact

The meter that starts before the cable does

It surprises a lot of teams that an ExpressRoute circuit starts billing the instant Azure issues its service key, well before the connectivity provider has plugged anything in and long before a single packet crosses it. The service key exists precisely so you can hand it to your provider to provision their side, so the gap between 'circuit created and billing' and 'circuit actually carrying traffic' can be days, weeks, or, for an abandoned circuit, forever. That design is reasonable, Microsoft is holding capacity for you, but it is exactly why a circuit a provider order never completed against keeps quietly charging until somebody deletes the resource in Azure.

Finding unprovisioned circuits across a subscription

Priya runs the cloud platform at a company that finished a datacentre exit last year. Azure Advisor's Cost tab is showing the 'Reduce costs by eliminating unprovisioned ExpressRoute circuits' recommendation against two subscriptions, and the estimated monthly saving is not trivial.

Rather than act on the Advisor card blind, Priya lists the circuits directly so she can see which are still in provider status 'Not provisioned' and separate a genuinely pending provisioning from the leftovers of the migration.

List every ExpressRoute circuit with its provider and circuit status, so the unprovisioned ones stand out from the live links.

$ az network express-route list --query "[].{name:name, provider:serviceProviderProvisioningState, circuit:circuitProvisioningState, sku:sku.family}" -o table
Name Provider Circuit Sku
---------------- --------------- -------- -----------
er-prod-uksouth Provisioned Enabled UnlimitedData
er-dc-migration NotProvisioned Enabled MeteredData
er-poc-westeu NotProvisioned Enabled MeteredData
# Two circuits sit in NotProvisioned. Both still bill the monthly port charge.

A circuit can be 'Enabled' on the Azure side (circuit status) while the provider side is still 'NotProvisioned'. It is the provider status that decides whether the link is actually carrying traffic, and the charge applies either way.

How Advisor decides an ExpressRoute circuit is wasted spenddeep dive

Two properties on the circuit tell the whole story. 'circuitProvisioningState' is the Azure side: it reads 'Enabled' as soon as the circuit resource exists, which is why a brand-new circuit looks 'Enabled' even though nothing is connected to it. 'serviceProviderProvisioningState' is the provider side, and it moves through 'NotProvisioned', 'Provisioning' and 'Provisioned'. A circuit only carries traffic once the provider side reaches 'Provisioned'. In the portal these appear as 'Circuit status' and 'Provider status' in the circuit's essentials.

Advisor watches the provider side. Its 'Reduce costs by eliminating unprovisioned ExpressRoute circuits' recommendation fires when a circuit has been in 'Not provisioned' for more than one month, on the reasoning that a provisioning genuinely in flight completes in days, not weeks, so a month of 'Not provisioned' means the order was abandoned or never placed. Crucially, the billing does not wait for any of this: the circuit is billed from the moment its service key is issued at creation, and that charge continues every month until the circuit is deleted in Azure, regardless of whether the provider side ever moves off 'NotProvisioned'.

The metered or unlimited choice in the SKU family, 'MeteredData' or 'UnlimitedData', changes how outbound data transfer is priced, but it does not change this: both carry a fixed monthly circuit charge that an unprovisioned circuit incurs in full while moving no data at all. That is why the safe action is deletion rather than resizing. There is no smaller SKU that makes an unused circuit worth keeping; the value of an unprovisioned circuit is zero, so the right cost is zero, which means removing the resource.

What is the impact of leaving an unprovisioned circuit in place?

The direct impact is a recurring charge for nothing. The circuit incurs its full monthly port charge for as long as the resource exists, and because it is never provisioned, it returns no connectivity, no resilience and no traffic in exchange. Unlike an oversized but used resource, there is no partial value to set against the cost; the entire charge is waste. Left alone, that charge does not lapse or self-correct, it simply repeats on every invoice until someone deletes the resource.

The second-order impact is that it hides in plain sight. An ExpressRoute circuit looks like infrastructure, so it tends to be assumed load-bearing and left untouched during cost reviews, while its provider status, the field that would reveal it is doing nothing, is rarely the thing anyone checks. The longer it sits, the more institutional memory of why it was created fades, which paradoxically makes teams more nervous about deleting it even though an unprovisioned circuit is the safest possible thing to delete.

There is no upside to leaving it. A genuinely pending circuit, one a provider is actively turning up, is the only exception, and Advisor's one-month threshold is designed to exclude exactly that case. Everything past it is recurring spend with a zero return, and the cost of inaction is simply that the charge keeps recurring, compounding into a meaningful annual figure for a resource nobody is using.

How do you remove an unprovisioned circuit safely?

Work the recommendation as a short, ordered checklist rather than a blind delete. The order matters: confirm there is no live provider order, then clear anything attached to the circuit, then delete it, so the operation cannot fail halfway or remove something genuinely pending.

1. Confirm the circuit is genuinely abandoned

For each flagged circuit, check 'serviceProviderProvisioningState' is still 'NotProvisioned' and confirm with the network team or provider that no order is in flight. Advisor's one-month threshold means a provisioning genuinely in progress is unlikely to be caught, but a quick confirmation costs nothing and rules out deleting a circuit a provider is days away from lighting up.

2. Clear anything attached before deleting

A circuit cannot be deleted while it has dependents. Remove any virtual network gateway connections, route filters, link authorisations and Global Reach configuration first. For an unprovisioned circuit these are usually empty, but list them to be sure, because a leftover authorisation or connection will block the delete with an error rather than silently.

3. Delete the circuit to stop the meter

Deleting the circuit resource in Azure is what actually stops the billing, and the charge ends in the same billing cycle. There is no separate deprovisioning step to fund for an unprovisioned circuit, because the provider side was never turned up. Capture Advisor's estimated saving against each deletion so the recurring, annualised figure lands in the savings plan.

4. Make the review recurring

Treat the Advisor cost recommendation as a standing report rather than a one-off sweep. Circuits get created for new migrations and proofs of concept all the time, so check the 'eliminate unprovisioned ExpressRoute circuits' recommendation on a regular cadence and confirm-then-delete each new arrival before it has compounded into months of wasted charge.

# 1. List circuits still on the provider side as NotProvisioned past the threshold.
az network express-route list \
  --query "[?serviceProviderProvisioningState=='NotProvisioned'].{name:name, rg:resourceGroup}" \
  -o table

# 2. For each abandoned circuit, clear link authorisations, then delete to stop billing.
RG="<resource-group>"
CIRCUIT="<circuit-name>"

for auth in $(az network express-route auth list \
    --circuit-name "$CIRCUIT" --resource-group "$RG" \
    --query "[].name" -o tsv); do
  az network express-route auth delete \
    --circuit-name "$CIRCUIT" --resource-group "$RG" --name "$auth"
done

# Deleting the circuit resource is what actually stops the monthly charge.
az network express-route delete --name "$CIRCUIT" --resource-group "$RG"
echo "$CIRCUIT deleted: monthly circuit charge stops this billing cycle."

Quick quiz

Question 1 of 5

When does an ExpressRoute circuit start incurring its monthly charge?

You can now treat an unprovisioned ExpressRoute circuit as exactly what it is: a private connection you are paying for and not using. You know it bills from the moment the service key is issued, that Azure Advisor flags any circuit stuck in 'Not provisioned' past a month, and how to confirm a circuit is abandoned, clear its dependents and delete it to stop the charge in the same billing cycle. The saving recurs every month you act on it rather than leave it.

Back to the library