Home / Azure

AzureRunbookAdvanced

Converting an Azure Storage account from LRS to ZRS in place: blockers, the conversion and what to watch

Add zone redundancy to a live storage account without copying data. Clear the blockers (archive blobs, boot diagnostics, NFS, failed-over accounts), start the conversion, track it, then add geo-redundancy.

Deepak Bhardwaj7 min read

Applies toAzure Storage general-purpose v2 and premium file share accounts, Azure CLI 2.60+ (az storage account migration), Az.Storage PowerShell

Goal

A production storage account is LRS, so one zone outage in the region can make it unavailable. You want ZRS, or GZRS later, without a data copy, a new account name or a connection-string change.

Customer-initiated conversion does this in place. It's a different operation from the SKU change that adds or removes geo-redundancy:

Change Method Downtime
LRS ↔ GRS / RA-GRS, GRS → LRS az storage account update --sku None
LRS → ZRS, GRS → GZRS, ZRS → LRS and the like (zone redundancy added or removed) Conversion: az storage account migration start, portal or support request None. Accounts with hierarchical namespace may see a pause of under 30 seconds
Anything else that conversion blocks, or a hard deadline Manual migration to a new account (AzCopy and others) App cut-over needed

Zone changes and geo changes are separate steps. To go from LRS to GZRS, do the conversion to ZRS, wait at least 24 hours, then change the SKU to GZRS. The other order also works.

Step 1: inventory the account

RG=rg-data
SA=stproddata01

az storage account show -g $RG -n $SA --query "{sku:sku.name, kind:kind, tier:accessTier, hns:isHnsEnabled, nfsv3:enableNfsV3, location:location, secondary:secondaryLocation, failoverInProgress:failoverInProgress}" -o jsonc

Check the target SKU is offered in the region. Not every region has availability zones, and ZRS and GZRS support differ by region, so check the current ZRS/GZRS region list in the Azure Storage redundancy documentation. A quick sanity check is whether the region lists zones for VMs:

az vm list-skus -l $(az storage account show -g $RG -n $SA --query location -o tsv) \
  --resource-type virtualMachines --query "[0].locationInfo[0].zones" -o tsv

Step 2: clear the blockers

Each of these stops or fails a conversion. Check them all before you submit.

Blocker How to check What to do
Account kind is GPv1, or premium block/page blob kind, sku from Step 1 Upgrade GPv1 to GPv2 first. Premium block blob needs a manual migration. Premium page blob can't be zone-redundant
Blobs in the archive tier Blob inventory, or a listing (below) ZRS has no archive tier. Move archived blobs to another account, or rehydrate them, before you convert
NFSv3 enabled for Blob enableNfsV3: true Conversion isn't supported. Plan a manual migration
Azure Files NFSv4.1 shares with public endpoint access File share protocol and network settings Disable public endpoint access, convert, then reconfigure
Account used for VM boot diagnostics VMs pointing at this account Disable boot diagnostics against it, or point VMs at managed boot diagnostics
Account was failed over (GRS → now LRS in the new primary) Account history and secondaryLocation Conversion isn't supported from that state. Use a manual migration
A recent redundancy change Activity Log Wait 24 hours after a zone conversion before the next change

Find archive-tier blobs. On large accounts, use blob inventory rather than a listing:

for c in $(az storage container list --account-name $SA --auth-mode login --query "[].name" -o tsv); do
  n=$(az storage blob list --account-name $SA --auth-mode login -c "$c" \
        --query "length([?properties.blobTier=='Archive'])" -o tsv --num-results "*")
  [ "$n" != "0" ] && echo "$c: $n archive blobs"
done

Find VMs whose boot diagnostics write to this account:

az vm list --query "[?diagnosticsProfile.bootDiagnostics.storageUri && contains(diagnosticsProfile.bootDiagnostics.storageUri, '$SA')].{vm:name, rg:resourceGroup}" -o table

# Switch a VM to managed boot diagnostics
az vm boot-diagnostics enable -g <vm-rg> -n <vm-name>

Calling az vm boot-diagnostics enable without --storage switches the VM to managed storage.

Warning

Don't delete archived blobs to get past the blocker without checking retention rules. Archived data is often there for legal or audit reasons. Early deletion from archive is charged, and rehydrating costs money and can take hours per blob. Agree the plan with the data owner first.

Step 3: confirm nothing depends on LRS behaviour

  • Locks: a ReadOnly lock on the account or resource group blocks the change. A CanNotDelete lock doesn't.
  • Policy: a policy that denies SKU changes, or that pins sku.name, will block the request. Check for an assignment that allows only certain SKUs.
  • IaC drift: if Bicep or Terraform declares Standard_LRS, the next pipeline run will try to change it back, or fail. Update the code to Standard_ZRS in the same change. Some Terraform provider versions treat a replication change as a replacement, so read the plan before you apply anything.
az lock list -g $RG -o table
az policy state list --resource "$(az storage account show -g $RG -n $SA --query id -o tsv)" \
  --query "[?complianceState=='NonCompliant'].{policy:policyDefinitionName, assignment:policyAssignmentName}" -o table

Step 4: start the conversion

az storage account migration start \
  --account-name $SA -g $RG \
  --sku Standard_ZRS \
  --name default \
  --no-wait

PowerShell:

Start-AzStorageAccountMigration -AccountName stproddata01 -ResourceGroupName rg-data -TargetSku Standard_ZRS -AsJob

--name is always default for customer-initiated conversions. If the request is rejected straight away, the error usually names the blocker: archive blobs, boot diagnostics, an unsupported region or an unsupported feature. Fix it and submit again.

Step 5: track it

az storage account migration show --account-name $SA -g $RG -o jsonc
Get-AzStorageAccountMigration -AccountName stproddata01 -ResourceGroupName rg-data |
  Select-Object DetailMigrationStatus, DetailTargetSkuName

The status moves from submitted, to in progress, to completed or failed. Exact strings vary by API version. The conversion usually starts within 72 hours of the request and has no completion SLA. Large accounts can take much longer. A failed conversion needs a support request.

Tip

If you have a hard deadline, such as a zone resilience audit or a planned zone maintenance window, a conversion is the wrong tool. Do a manual migration with AzCopy to a new ZRS account, where you control the timing.

While it runs, the account stays fully available. Keep normal monitoring on, and watch the account's Availability and SuccessE2ELatency metrics for anything unusual:

SA_ID=$(az storage account show -g $RG -n $SA --query id -o tsv)
az monitor metrics list --resource $SA_ID --metric Availability SuccessE2ELatency \
  --interval PT1H --aggregation Average -o table

Step 6: verify and finish

az storage account show -g $RG -n $SA --query "sku.name" -o tsv
# Standard_ZRS

Then:

  1. Update IaC to the new SKU and run a plan or what-if. It should show no changes.
  2. If you're going on to GZRS, wait at least 24 hours, then run az storage account update -g $RG -n $SA --sku Standard_GZRS. Adding geo-redundancy incurs a one-time egress charge to copy the whole account to the secondary region.
  3. Re-enable anything you turned off for the conversion, such as NFSv4.1 public endpoints, once it's complete.
  4. Record the change and the new SKU in the DR documentation.

Costs

The conversion itself carries no up-front charge. After it, ZRS storage and transactions cost more per GB than LRS, so check the current pricing for your region and tier before you roll this out to a whole fleet. Rehydrating archived data, and moving it to another account, are charged separately.

Prevent it next time

  • Make ZRS (or GZRS) the default in your storage module, and add an audit policy that flags LRS accounts in production subscriptions.
  • Keep boot diagnostics on managed storage, so VM accounts never block a redundancy change.
  • Keep archive-tier data in dedicated accounts that stay on LRS or GRS by design.
  • Batch conversions by region, and record the request date for each, so a "still submitted after 72 hours" account is spotted and raised with support.