The fastest way to cut a monthly Azure bill is to work in a fixed order: set budgets so you can see the effect of each change, delete orphaned resources such as unattached disks and static public IPs, deallocate or schedule idle VMs, right-size what remains with Azure Advisor, apply Azure Hybrid Benefit where you already own licences, and only then buy reservations and savings plans for the clean baseline. Commitments bought before cleanup lock in waste, because a discount reduces the rate you pay, not the amount you use.
Who this is for and what you will have at the end
This checklist is for Azure administrators, platform teams and FinOps practitioners who own one or more subscriptions and need a repeatable way to reduce spend without breaking workloads.
At the end you will have:
- Budgets with actual and forecasted alerts on the scopes you own.
- Azure Resource Graph queries that list orphaned disks, public IPs, network interfaces, NAT gateways, gateways and load balancers.
- A list of VMs that are stopped but still allocated, and auto-shutdown on non-production machines.
- Advisor right-sizing recommendations tuned to your own CPU threshold and lookback period.
- A decision on reservations versus savings plans, based on Microsoft's recommended purchase sequence.
If you are still moving workloads into Azure, the landing-zone and subscription design in the enterprise Azure cloud migration playbook makes every step below easier, because costs land on predictable scopes.
Prerequisites
| Task | What you need |
|---|---|
| View budgets | Read access on the scope |
| Create or edit budgets | Owner, Contributor or Cost Management Contributor |
| Run Resource Graph queries | Read access to the subscriptions you query |
| Change Advisor right-sizing filters | Advisor permissions on the subscription (the option is disabled without them) |
| Exchange or refund reservations | Owner or Reservation administrator on the reservation order |
| Change VM licence type or auto-shutdown | Contributor-level rights on the VM |
You also need Azure CLI or Azure PowerShell. Resource Graph queries can run from Resource Graph Explorer in the portal, az graph query or Search-AzGraph. A brand-new subscription can take up to 48 hours before all Cost Management features, including budgets, are available.
Step 1: Set budgets before you change anything
Budgets don't stop resources, but they give you a baseline and an early warning. Create one per subscription or resource group that has an owner.
- In the Azure portal, open the subscription (or resource group) and select Budgets, then Add.
- Confirm the scope, add filters if the budget should cover only some costs, name it, and choose a reset period of monthly, quarterly or annually.
- Set an expiration date. When a budget expires it's deleted.
- Select Next and add alert conditions. Use the Type field to switch between Actual and Forecasted.
Points to know when you configure alerts:
- Each budget needs at least one threshold and one email address, and supports up to five thresholds and five email addresses.
- Cost data is typically available within 8-24 hours and budgets are evaluated every 24 hours, so alerts aren't real time.
- Budget evaluation includes reservation and purchase data. To evaluate first-party Azure consumption only, add the filters Publisher Type: Azure and Charge Type: Usage.
- Action groups are supported only at subscription and resource group scopes. Use them for webhooks or automation rather than email alone.
The Azure CLI equivalent, based on Microsoft's example, creates a monthly budget on a resource group with an 80% alert routed to an action group:
az consumption budget create-with-rg \
--amount 5000 \
--budget-name rg-app-prod-monthly \
-g rg-app-prod \
--category Cost \
--time-grain Monthly \
--time-period '{"start-date":"2026-10-01","end-date":"2027-09-30"}' \
--notifications "{\"Key1\":{\"enabled\":\"true\", \"operator\":\"GreaterThanOrEqualTo\", \"contact-emails\":[], \"threshold\":80.0, \"contact-groups\":[\"$ActionGroupId\"]}}"Step 2: Remove orphaned resources
Deleting a VM doesn't delete its disks by default, and public IPs, NICs, NAT gateways and gateways are often left behind after a migration or a rebuild. These are the safest savings because nothing is using them, but deletion is permanent, so review every result with the resource owner first.
Unattached managed disks
An attached managed disk has the VM's resource ID in its managedBy property; an unattached one has managedBy set to null. List them per subscription:
az disk list --query '[?managedBy==`null`].[id]' -o tsvBefore deleting, run az disk show and check LastOwnershipUpdateTime, which shows when the disk was unattached. Take a snapshot if there is any doubt. Advisor also raises a preview recommendation, Review disks that aren't attached to a VM and evaluate if you still need the disks, which excludes Azure Site Recovery replica disks.
Unattached static public IPs
Static public IPs are charged whether or not they're associated with a resource. This Resource Graph query, adapted from Microsoft's FinOps networking guidance, lists static IPs that aren't attached to an IP configuration or a NAT gateway:
resources
| where type =~ 'Microsoft.Network/publicIPAddresses'
and isempty(properties.ipConfiguration)
and isempty(properties.natGateway)
and properties.publicIPAllocationMethod =~ 'Static'
| project id, name, SKUName = tostring(sku.name), resourceGroup, location, subscriptionIdBefore you delete an address, check DNS records and partner allow lists. Once a public IP is deleted, the address can't be recovered.
Other networking leftovers
| Resource | Why it costs money | Resource Graph filter |
|---|---|---|
| NAT gateway with no subnets | Hourly and data processing charges | type == "microsoft.network/natgateways" and isnull(properties.subnets) or array_length(properties.subnets) == 0 |
| Virtual network gateway with no connections | Hourly charge by SKU | Gateways with no matching microsoft.network/connections resource |
| Standard load balancer with no backend pools | Standard load balancers incur costs when idle | array_length(properties.backendAddressPools) == 0 and sku.name != 'Basic' |
| DDoS protection plan with no virtual networks | Fixed monthly charge | isnull(properties.virtualNetworks) or array_length(properties.virtualNetworks) == 0 |
| ExpressRoute circuit not provisioned | Monthly charge without traffic | properties.serviceProviderProvisioningState == "NotProvisioned" |
| Network interface with no VM or private endpoint | No direct charge, but often keeps a public IP alive | isnull(properties.virtualMachine) and isnull(properties.privateEndpoint) |
For example, idle NAT gateways:
resources
| where type == "microsoft.network/natgateways"
| where isnull(properties.subnets) or array_length(properties.subnets) == 0
| project id, name, SKUName = tostring(sku.name), location, resourceGroup, subscriptionIdAdvisor surfaces some of the same items on its Cost tab, including Delete Azure virtual network gateways with no connections, Delete or provision ExpressRoute circuits in a not-provisioned state and Unused or empty App Service plan, all in preview at the time of writing.
Step 3: Stop paying for idle compute
A VM shut down from inside the guest OS, or with the PowerOff operation, sits in the Stopped state, which is still billed for compute. Only Stopped (deallocated) releases the hardware and stops compute charges. Disks and networking continue to bill in both cases.
Find VMs that are stopped but still allocated across every subscription you can read:
Resources
| where type == 'microsoft.compute/virtualmachines'
| extend PowerState = tostring(properties.extended.instanceView.powerState.code)
| where PowerState == 'PowerState/stopped'
| project name, resourceGroup, subscriptionId, PowerStateDeallocate them, or delete them if they're no longer needed. For development and test VMs that only run in working hours, enable auto-shutdown: open the VM, select Auto-shutdown under Operations, switch it on, set the time and optionally a notification email or webhook. The portal's time zone defaults to UTC, so set it explicitly. From the CLI, --time takes a UTC time in hhmm format:
az vm auto-shutdown -g rg-dev -n vm-dev-01 --time 1800Step 4: Right-size with Azure Advisor
Advisor's Right-size or shutdown underutilized virtual machines recommendation (and the scale set equivalent) uses CPU, memory and outbound network metrics:
- Shutdown is recommended when P95 of maximum CPU summed across cores is below 3%, P100 of average CPU over the last 3 days is 2% or less, and outbound network utilization is below 2% over seven days.
- Resize targets a cheaper SKU where user-facing workloads would stay at or below 40% P95 CPU and network and 60% P99 memory, and non-user-facing workloads at or below 80% for each. The new SKU must keep the same Accelerated Networking and Premium Storage capabilities and be available in the region.
- Burstable recommendations suggest B-series sizes for workloads with low average CPU but occasional spikes, where the VM doesn't use accelerated networking.
The default lookback is seven days. You can change it to 7, 14, 21, 30, 60 or 90 days; recommendations can take up to 48 hours to refresh. A longer lookback avoids resizing a VM that is busy at month end.
To show only recommendations for VMs below a CPU level you're comfortable acting on, open Advisor, select Configuration, then the VM/Virtual Machine Scale Sets right sizing tab, select the subscriptions, select Edit, choose the average CPU value and select Apply. The filter can take up to 24 hours to apply.
Two limitations matter when you act on these recommendations:
- Estimated savings use retail rates and ignore negotiated discounts, so real savings are usually lower.
- Recommendations ignore your reservations and savings plans. A cross-series resize can move a VM off a reserved size and raise the bill. Check coverage before resizing reserved VMs.
Use Dismiss or Postpone for VMs sized for planned growth, disaster recovery or SKU uniformity, so the list stays actionable.
Step 5: Apply licences you already own
Azure Hybrid Benefit for Windows Server lets you use on-premises Windows Server core licences with active Software Assurance or qualifying subscription licences. Each VM needs at least 8 core licences, and the benefit is valid only during the Software Assurance or subscription term. Changing the licence type only changes a metadata flag; the VM doesn't restart.
List Windows Server VMs that already use the benefit, then convert the ones that qualify:
az vm list --query "[?licenseType=='Windows_Server']" -o table
az vm update --resource-group rg-app-prod --name vm-app-01 --set licenseType=Windows_ServerIn the portal, the same setting is under the VM's Operating system page as Azure Hybrid Benefit. A VM reservation or a savings plan for compute covers only the compute cost, not the Windows software cost, so Hybrid Benefit for Windows Server stacks with them rather than overlapping. (The separate savings plan for databases does cover some SQL Server software costs, so check before combining it with SQL Server licences you already own.)
Step 6: Commit with reservations and savings plans
Once the baseline is clean, commitments give the largest discount on what remains.
| Reservation | Savings plan | |
|---|---|---|
| Commitment | A specific SKU or family, usually in one region | A fixed spend per hour |
| Term | 1 or 3 years | 1 or 3 years |
| Applies to | Matching resources in the selected scope | Eligible compute or database usage across regions |
| Best for | Stable workloads that won't change size, family or region | Workloads that change family, service or region |
| Cancellation | Refunds allowed up to 50,000 USD of canceled commitment per rolling 12 months | Can't be canceled or refunded |
Reservations can reduce costs by up to 72% compared with pay-as-you-go prices, and up-front and monthly payment cost the same in total. Savings plans come in two kinds: Savings plan for compute (Virtual Machines, App Service, Functions premium plan, Container Instances, Dedicated Host, Container Apps and others) and Savings plan for databases. Unused hourly savings plan commitment expires; it doesn't roll over.
Microsoft's recommended sequence is:
- Right-size first. Discounts reduce rates, not waste.
- Exchange underused reservations for configurations that fit.
- Trade in underused reservations for savings plans where usage varies.
- Buy new reservations only for stable workloads.
- Buy a savings plan sized to the remaining optimized baseline.
Use the purchase recommendations in Advisor (for example Consider virtual machine reserved instance to save over the on-demand costs and Consider purchasing a savings plan to unlock lower prices) or in the purchase experience in the portal. Also act on Configure automatic renewal for the expiring reservations, because an expired reservation falls back to on-demand rates without any outage to tell you.
Plan for the exchange policy change: reservations purchased after 1 February 2027 for services that savings plans cover, such as Virtual Machines, App Service and SQL Database, won't be exchangeable. Reservations bought before that date keep one final exchange. Instance size flexibility and the refund limit don't change.
Verify the savings
- Cost analysis. Compare the month after cleanup with the baseline your budgets captured. Remember that cost data lags by up to a day.
- Reservation utilization. Open Reservations in the portal and check utilization for each order. Low utilization means the reservation no longer matches the workload; exchange it or trade it in.
- Re-run the queries. Schedule the Resource Graph queries above, for example monthly, so new orphans are caught early.
- Advisor Cost tab. Confirm dismissed or postponed recommendations still have a valid reason.
Troubleshooting
You can't create a budget on a new subscription. Cost Management features can take up to 48 hours to become available on a new subscription.
Budget alert emails never arrive. Add azure-noreply@microsoft.com to your approved senders list; the messages often land in junk mail.
Budget created with PowerShell sends no notifications. Microsoft notes that budgets created with PowerShell don't send notifications, and recommends the REST API for programmatic creation. Microsoft Customer Agreement customers should use the Budgets REST API.
Advisor recommendations didn't change after you changed the lookback period. Allow up to 48 hours for the lookback change and up to 24 hours for a CPU filter change.
The bill went up after a right-size. The new size probably isn't covered by your reservation. Exchange the reservation to the new size or trade it in for a savings plan.
Exchange fails with an error about the purchase amount. The new purchase must be equal to or greater than the amount returned. Reduce the quantity you return or increase the quantity you buy.
A deleted disk or public IP was still needed. Neither can be recovered after deletion. Restore the data from a snapshot or backup and update DNS for the new address. Taking a snapshot first, and tagging resources with an owner, prevents this.
Checklist
- Budgets with actual and forecasted alerts on every owned subscription and key resource group.
- Unattached disks reviewed, snapshotted where needed, and deleted.
- Unattached static public IPs, idle NAT gateways, gateways, load balancers, DDoS plans and unprovisioned circuits removed.
- No VMs left in Stopped (allocated) state; auto-shutdown on non-production VMs.
- Advisor lookback and CPU filter set; right-size recommendations actioned or dismissed with a reason.
- Azure Hybrid Benefit enabled on every eligible Windows Server VM.
- Reservations exchanged or traded in where underused; new reservations only for stable workloads; savings plan sized to the clean baseline.
- Automatic renewal configured for expiring reservations, and the February 2027 exchange change noted.
References
- Tutorial: Create and manage budgets
- Find and delete unattached Azure managed and unmanaged disks (Azure portal)
- Azure CLI: Find and delete unattached managed and unmanaged disks
- FinOps best practices for Networking
- States and billing status of Azure Virtual Machines
- Azure Resource Graph advanced query samples
- Auto-shutdown a VM
- Optimize VM or VMSS spend by resizing or shutting down underutilized instances
- Azure Advisor cost recommendations reference
- Explore Azure Hybrid Benefit for Windows VMs
- What are Azure Reservations?
- What are savings plans?
- Decide between a savings plan and a reservation
- Self-service exchanges and refunds for Azure Reservations