Azure disk pricing punishes the default choice. Premium SSD v2 decouples capacity from IOPS and throughput, so you stop buying a larger disk purely to get faster IO, and ephemeral OS disks remove the remote OS disk bill entirely for anything you are willing to reimage. This post covers where each one fits, the documented ceilings rather than invented benchmarks, the commands to provision both, and the two template mistakes that will fail a deployment outright.
Benchmark methodology
Measure at three layers to avoid false conclusions: guest IO tool, VM metrics, and disk metrics.
- Linux fio
# Random read write 4k mix for OLTP
sudo fio \
--name=randrw --filename=/mnt/data/testfile \
--rw=randrw --rwmixread=70 \
--bs=4k --iodepth=32 --numjobs=8 \
--ioengine=libaio --runtime=120 --time_based --group_reporting
- Windows DiskSpd
# 64k sequential read for backup or analytics
DiskSpd.exe -d120 -b64K -o32 -t8 -Sh -r -w0 C:\test\testfile.dat
- Collect platform metrics
- VM: Data Disk IOPS Consumed Percentage, VM Uncached Bandwidth Consumed Percentage, Queue Depth, Latency.
- Disk: Read Ops per second, Write Ops per second, Bytes per second.
What the platform will actually give you
This section used to carry a table of IOPS and p99 latency figures presented as a test run. They were not measured on anything, so they have been removed rather than dressed up. I have not benchmarked these disks in production, and an invented latency figure is worth less than an honest ceiling.
What the documentation does support is the budget the platform will sell you. Premium SSD v2 includes 3,000 IOPS and 125 MB/s free on every disk. Above 6 GiB the IOPS ceiling rises by 500 per GiB, so reaching the full 80,000 IOPS needs a disk of at least 160 GiB, and throughput is provisioned at 0.25 MB/s for each IOPS you set. Verified against Microsoft’s managed disk type documentation on 26 September 2026.
Those are disk ceilings, not workload results. The VM SKU imposes its own uncached IOPS and bandwidth caps, and on most sizings that cap binds before the disk does. Measure with fio or DiskSpd against your own SKU and region, and watch the VM counters alongside the disk counters, or you will tune a disk that was never the constraint.
SKU comparison and what to use when
| Capability | Premium SSD v2 (data disk) | Premium SSD (OS or data) | Ultra Disk |
|---|---|---|---|
| OS disk support | No | Yes | No |
| Host caching | No | Yes | No |
| Max IOPS per disk | 80,000 | 20,000 | 400,000 |
| Max throughput per disk | 2,000 MB/s | 900 MB/s | 10,000 MB/s |
| Performance control | Set capacity, IOPS and throughput independently | Fixed tier by size, with optional performance tiering on some sizes | Set IOPS and throughput independently |
| Cost model | Capacity plus provisioned IOPS plus throughput | Fixed by size tier, plus optional performance tier uplift | Capacity plus provisioned IOPS plus throughput |
| Best for | Databases, queues, hot logs, game servers | OS disks and general workloads on fixed tiers | Extreme transactional or analytics peaks |
Three numbers in that table were wrong on this page until 26 September 2026, and they were wrong in the direction that costs money. Premium SSD v2 tops out at 2,000 MB/s, not 1,200. Ultra Disk reaches 400,000 IOPS and 10,000 MB/s, not 160,000 and 2,000. If you sized against the old figures you may have reached for Ultra where v2 would have carried the workload at a lower bill, or written off v2 for a throughput target it can in fact meet.
Ephemeral OS disks
- Store the OS on local SSD or NVMe of the VM. No remote managed OS disk. Ideal for stateless fleets that can be reimaged. AKS node pools are the obvious case, and GitOps fleet management for AKS covers the reimage workflow that makes it safe to rely on.
- Not for long lived pets. No snapshots or backup. Plan for reimage and use configuration management.
Cost scenarios
Focus on performance per pound, not raw cheapest. The same discipline applies to compute, where what Azure actually charges for a stopped resource catches most people out at least once.
Scenario A small database that needs 8k IOPS and 250 MBps with 256 GiB of data.
- Premium SSD v2 single disk set to 8,000 IOPS and 300 MBps.
- Legacy Premium SSD would need a larger tier or multiple striped disks to reach 8k IOPS, which lifts capacity and cost you do not need.
- Result fewer resources, simpler ops, lower £ per transaction.
Scenario B read heavy analytics window with daily peaks
- Keep v2 at a low baseline, then raise IOPS and throughput for the 6 hour window using an automated az disk update in a scheduled job. A timer-triggered Function or a Logic App both do the job, and the trade-offs between the two are covered separately. You pay for the higher provisioned figures only while they are configured.
- There is a cap on how often you can do that, and it is easy to miss: Premium SSD v2 performance can be adjusted four times in any 24 hour period, and creating the disk counts as one of them. A daily up and down cycle fits comfortably. A job that chases load hour by hour does not, and will start failing its own scale-down step. Per Microsoft’s Premium SSD v2 deployment guidance, checked 26 September 2026.
How to estimate
- v2 monthly cost equals capacity charge plus IOPS rate times provisioned IOPS plus MBps rate times provisioned MBps. Rates vary by region. Use the workbook calculator link below to plug your figures in.
- For Premium SSD tiers, monthly cost equals the tier price times count of disks.
IaC and commands that matter
Create Premium SSD v2 data disk and attach
Azure CLI
# Create disk with explicit performance
az disk create -g $RG -n data-pv2 --size-gb 256 \
--sku PremiumV2_LRS --zone 1 \
--disk-iops-read-write 8000 \
--disk-mbps-read-write 300
# Attach to a VM at LUN 0, no host caching on v2
az vm disk attach -g $RG --vm-name $VM --name data-pv2 --lun 0 --caching None
# Change performance later without downtime
az disk update -g $RG -n data-pv2 \
--disk-iops-read-write 12000 \
--disk-mbps-read-write 500
PowerShell
$cfg = New-AzDiskConfig -Location $loc -Zone 1 -DiskSizeGB 256 `
-AccountType PremiumV2_LRS -DiskIOPSReadWrite 8000 -DiskMBpsReadWrite 300 -CreateOption Empty
New-AzDisk -ResourceGroupName $rg -DiskName "data-pv2" -Disk $cfg
$vm = Get-AzVM -ResourceGroupName $rg -Name $vmName
$disk = Get-AzDisk -ResourceGroupName $rg -Name "data-pv2"
$vm = Add-AzVMDataDisk -VM $vm -Lun 0 -ManagedDiskId $disk.Id -CreateOption Attach -Caching None
Update-AzVM -VM $vm -ResourceGroupName $rg
Terraform
resource "azurerm_managed_disk" "data_pv2" {
name = "data-pv2"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
storage_account_type = "PremiumV2_LRS"
disk_size_gb = 256
create_option = "Empty"
disk_iops_read_write = 8000
disk_mbps_read_write = 300
zone = 1
}
resource "azurerm_virtual_machine_data_disk_attachment" "vm_data" {
managed_disk_id = azurerm_managed_disk.data_pv2.id
virtual_machine_id = azurerm_linux_virtual_machine.vm.id
lun = 0
caching = "None" # v2 does not support host caching
}
Ephemeral OS disk on a scale set
Bicep
param location string
param vmssName string
param adminUser string
resource vmss 'Microsoft.Compute/virtualMachineScaleSets@2024-03-01' = {
name: vmssName
location: location
sku: {
name: 'Standard_D2ads_v6'
capacity: 3
tier: 'Standard'
}
zones: [ '1' ]
properties: {
upgradePolicy: { mode: 'Rolling' }
virtualMachineProfile: {
storageProfile: {
osDisk: {
createOption: 'FromImage'
diffDiskSettings: {
option: 'Local'
placement: 'NvmeDisk'
}
}
dataDisks: [ ]
}
osProfile: {
computerNamePrefix: 'web'
adminUsername: adminUser
}
networkProfile: { }
}
}
}
Two details in that template will stop a deployment before it starts. The placement value is NvmeDisk, not Nvme, and the three accepted values are CacheDisk, ResourceDisk and NvmeDisk. NVMe placement also requires API version 2024-03-01 or later on the scale set resource, so an older apiVersion rejects it even when the value is spelled correctly. Both were wrong in the sample on this page until 26 September 2026. See the ephemeral OS disk documentation for the size requirements, which differ by image and by SKU.
The newsletter
Get the next Azure fix like this one by email
Subscribe and get the free 8-page Intune troubleshooting field guide (PDF), then new fixes about twice a month. From a Microsoft MVP.
Autoscale on disk pressure
CLI
# Create autoscale and rules for VMSS
az monitor autoscale create -g $RG --resource $VMSS_ID -n vmss-autoscale \
--min-count 2 --max-count 10 --count 3
# Scale out if VM Uncached IOPS is hot
az monitor autoscale rule create -g $RG --autoscale-name vmss-autoscale \
--condition "VM Uncached IOPS Consumed Percentage > 90 avg 10m" --scale out 1
# Scale in when cooled
az monitor autoscale rule create -g $RG --autoscale-name vmss-autoscale \
--condition "VM Uncached IOPS Consumed Percentage < 40 avg 15m" --scale in 1
Alerting for throttling
CLI
# Alert when a VM is near the disk IOPS cap
az monitor metrics alert create -g $RG -n disk-iops-near-cap \
--scopes $VM_ID \
--condition "avg Data Disk IOPS Consumed Percentage > 90" \
--window-size 5m --evaluation-frequency 1m \
--description "IOPS nearing provisioned limit" --action-group $AG_ID
# Alert on bandwidth capping as well
az monitor metrics alert create -g $RG -n disk-mbps-near-cap \
--scopes $VM_ID \
--condition "avg VM Uncached Bandwidth Consumed Percentage > 90" \
--window-size 5m --evaluation-frequency 1m --action-group $AG_ID
ARM metric alert
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Insights/metricAlerts",
"name": "disk-iops-near-cap",
"apiVersion": "2018-03-01",
"location": "global",
"properties": {
"severity": 2,
"enabled": true,
"scopes": ["/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Compute/virtualMachines/<vm>"] ,
"evaluationFrequency": "PT1M",
"windowSize": "PT5M",
"criteria": {
"allOf": [
{
"metricName": "Data Disk IOPS Consumed Percentage",
"operator": "GreaterThan",
"timeAggregation": "Average",
"threshold": 90
}
]
}
}
}
]
}
Where this bites in practice
I have not run this workload in production, so there are no measured before and after numbers here and I would rather say that than invent a pair. What the pricing and metric documentation supports is the shape of the problem: a burst-sensitive API on Premium SSD v1 pays for provisioned IOPS it does not use at 3am and still throttles at lunchtime, because the disk tier is a fixed ceiling rather than a budget. Premium SSD v2 decouples capacity from IOPS and throughput, which is why the alert on Data Disk IOPS Consumed Percentage above is the metric worth wiring up first. It tells you whether you are paying for headroom or actually short of it.
FinOps checklist
- Tag every disk with owner, environment, RPO RTO, and performance intent. Enforce it with policy at management group scope rather than asking nicely, as in the Azure landing zone governance model.
- Right-size monthly by checking IOPS and MBps consumed versus provisioned. Trim v2 settings when peaks pass.
- Prefer v2 for any workload with nonlinear performance needs. Keep OS on Premium SSD or Ephemeral OS disks.
- Reserve capacity for VMs where appropriate but keep disks flexible.
- Export metrics to Log Analytics and review weekly. Act on any chart that rides over 85 percent for more than 5 minutes.



