How to Find (and Safely Delete) Orphaned Disks in Azure
Orphaned managed disks are the single most common piece of waste we find in Azure environments — and one of the easiest to fix. When a VM is deleted, its OS and data disks are not deleted by default (unless someone ticked "delete with VM"). The disk stays behind, fully billed, attached to nothing, doing nothing. Multiply that by years of VM churn, AVD pools, dev experiments and migrations, and most tenants are carrying a quiet four-to-five-figure annual bill for storage nobody is using.
What an orphaned disk actually costs
Managed disks bill for provisioned capacity, not usage. Attached or not, running VM or not, the meter runs. Approximate pay-as-you-go list prices (LRS, varies by region):
| Disk | Size | ~Monthly list price | ~Annual if forgotten |
|---|---|---|---|
| Premium SSD P10 | 128 GB | ~$20 | ~$240 |
| Premium SSD P20 | 512 GB | ~$81 | ~$970 |
| Premium SSD P30 | 1 TB | ~$135 | ~$1,620 |
| Standard SSD E20 | 512 GB | ~$25 | ~$300 |
Ten forgotten P20s is roughly $9,700 a year — for nothing. ZRS redundancy costs ~50% more again.
Method 1 — the Azure Portal (quick spot-check)
- Search for Disks in the portal.
- Add the column Disk state, then filter it to Unattached.
- Sort by size descending — your biggest savings are at the top.
Fine for a one-off look at a single subscription. It does not scale to a tenant, and it tells you nothing about the traps below.
Method 2 — Azure Resource Graph (the right way at scale)
Resource Graph queries every subscription you can read in one shot. In Cloud Shell or anywhere az is installed:
az graph query -q "
Resources
| where type =~ 'microsoft.compute/disks'
| where isempty(managedBy) and properties.diskState == 'Unattached'
| extend sizeGB = toint(properties.diskSizeGB), sku = tostring(sku.name)
| project name, resourceGroup, subscriptionId, location, sizeGB, sku
| order by sizeGB desc"
The two conditions matter: managedBy empty (no VM owns it) and diskState == 'Unattached'. A disk in Reserved state, for example, belongs to a stopped-but-allocated VM.
The traps: disks that look orphaned but aren't
This is where most cleanup scripts go wrong. We learned these the hard way building our own scanner, and they're the difference between savings and an incident:
1. Azure Site Recovery replica disks
ASR keeps replica disks in your DR region that report as Unattached — because no VM is attached yet. They're named ms-asr-* and are actively written to by replication, linked to a Recovery Services vault. Delete one and you've silently broken your disaster recovery. Exclude anything matching ms-asr- or tagged for Site Recovery from any cleanup.
2. Disks on deallocated VMs
A stopped (deallocated) VM stops billing compute, but its disks keep billing in full. These are not orphaned — but they are a separate finding worth its own review: if the VM has been off for months, snapshot and delete the disks, or delete the whole VM.
3. Recently detached disks
A disk detached yesterday might be mid-maintenance. Check properties.timeCreated and your change records before assuming abandonment. A grace period (below) makes this a non-issue.
4. Snapshots are a different cleanup
Snapshots in AzureBackupRG_* resource groups are Azure Backup instant-restore points — service-managed, don't touch. Old manual snapshots whose source disk still exists may be deliberate DR retention. The genuinely safe target is disconnected snapshots whose source disk no longer exists.
The safe deletion workflow
- Exclude the traps —
ms-asr-*, backup RGs, anything taggedDoNotDelete. - Snapshot first. A snapshot of a 512 GB disk costs a fraction of the disk itself:
az snapshot create -g RG -n disk01-final-snap --source disk01 --incremental true - Tag and announce.
az disk update -g RG -n disk01 --set tags.DeleteAfter=2026-07-15— then tell the owning team. - Wait the grace period (14–30 days is typical), then delete:
az disk delete -g RG -n disk01 --yes - Retire the snapshot after a further quarter if nobody has needed it.
Or let the scanner do all of this for you. The CloudFinOpsKit Tool ($25, one-click, read-only) finds every unattached disk across your whole tenant, automatically excludes Site Recovery replicas and backup snapshots, prices each finding from your actual billed cost (falling back to live retail rates), and gives you the exact delete commands — alongside 75+ other checks.
Want the manual route first? Grab the free Azure Cost Review Checklist and make orphaned-disk review a monthly habit.
Stop them coming back
- Set "Delete with VM" on OS disks at creation (
--os-disk-delete-option Delete). - Enforce an owner tag via Azure Policy so every disk has a human to ask.
- Run the scan monthly — disk churn never stops; your review cadence shouldn't either.
FAQ
Do unattached disks really cost full price?
Yes — managed disks bill provisioned capacity regardless of attachment or VM power state. The meter only stops at deletion.
Are ms-asr-* disks safe to delete?
No. They're Azure Site Recovery replicas that only look unattached. Deleting them breaks replication. Exclude them always.
Should I delete or snapshot-then-delete?
Snapshot first, always. It costs little, and it converts an irreversible action into a reversible one during your grace period.
Related reading: the full 47-point Azure cost optimization checklist · Reserved Instances vs Savings Plans · the best Azure cost tools in 2026