Home / Azure

AzureTroubleshootingBeginner

Azure resource locks: ScopeLocked errors, ReadOnly side effects and managing locks safely

A delete, scale-out, key listing or backup fails with ScopeLocked. Find the lock (it may be inherited), understand ReadOnly side effects and change locks without leaving production unprotected.

Deepak Bhardwaj5 min read

Applies toAzure Resource Manager management locks (CanNotDelete, ReadOnly), Azure CLI 2.x, Az PowerShell

Symptoms

  • A deployment, delete or portal action fails with ScopeLocked: "The scope '/subscriptions/.../resourceGroups/rg-app' cannot perform write operation because following scope(s) are locked".
  • A pipeline that used to work now fails on a resource nobody touched.
  • Odd failures with no lock-related wording: storage keys won't list, a VM won't start, Azure Backup reports errors.

Management locks apply to everyone, including Owners. They are inherited from the subscription and resource group down to every resource, so the lock blocking you is often not on the resource you are changing.

The two lock types

Lock Blocks Allows
CanNotDelete (Delete in the portal) Deleting the resource and anything under the locked scope Reads and updates
ReadOnly Every write and delete, plus some POST operations GET operations

Locks act on the management plane (Azure Resource Manager). They do not stop data-plane operations such as deleting a blob or dropping a table inside a database.

Find the lock

List locks at every level that applies to the resource:

# Locks directly on the resource and inherited from its parents
az lock list --resource-group rg-app-prod \
  --resource-name stappprod01 --resource-type Microsoft.Storage/storageAccounts \
  --namespace "" -o table

# Every lock in the resource group (including on child resources)
az lock list --resource-group rg-app-prod -o table

# Every lock in the subscription
az lock list --query "[].{name:name, level:level, scope:id}" -o table

The id shows where the lock lives. A lock whose ID ends in /resourceGroups/rg-app-prod/providers/Microsoft.Authorization/locks/... covers the whole group.

PowerShell equivalent:

Get-AzResourceLock -ResourceGroupName rg-app-prod |
  Select-Object Name, Properties, ResourceId

ReadOnly side effects that catch people out

ReadOnly blocks more than you would expect, because some operations that only read data are implemented as POST or write requests.

What fails under a ReadOnly lock Why
Listing storage account keys (portal, az storage account keys list, tools that fetch keys) Listing keys is a POST action
Starting, restarting or resizing a VM Each is a write on the VM
Viewing App Service files in some tools, or changing app settings Writes to the site configuration
AKS scale-out or upgrades when the node resource group is locked The cluster can't create or update VMSS instances
Adding a subnet, private endpoint or peering on a locked VNet Writes to the VNet

CanNotDelete has its own trap: Azure Backup cleans up old restore point collections in the VM's resource group. A delete lock on that group stops the clean-up, and once the restore point limit is reached, new backups fail. Microsoft documents this case; keep restore point collections in a resource group without a delete lock.

Warning

Don't put ReadOnly locks on resource groups that hold running workloads. It looks like strong protection, but it breaks scaling, patching, certificate renewal and backups. Use CanNotDelete for production and RBAC to control who can change things.

Removing or changing a lock

You need Microsoft.Authorization/locks/* permissions. Among built-in roles, Owner and User Access Administrator have them; Contributor does not.

The safe pattern for a planned change:

# 1. Record the lock so you can put it back exactly
az lock show --name lock-prod-nodelete --resource-group rg-app-prod -o json > lock-backup.json

# 2. Remove it
az lock delete --name lock-prod-nodelete --resource-group rg-app-prod

# 3. Make the change
# ...

# 4. Recreate it with the same name, type and notes
az lock create --name lock-prod-nodelete --resource-group rg-app-prod \
  --lock-type CanNotDelete --notes "Production - change via CAB only"

Caution

The gap between steps 2 and 4 is when accidents happen. Do it in one script or pipeline run, add the change number to the lock notes, and never leave "I'll put it back later" for the end of the day.

To lock a single resource instead of a group:

az lock create --name nodelete-sql --lock-type CanNotDelete \
  --resource-group rg-data-prod --resource-name sql-prod-01 \
  --resource-type Microsoft.Sql/servers

Deployments and locks

  • Bicep/ARM deployments in Complete mode try to delete resources that are not in the template. A CanNotDelete lock makes the whole deployment fail, which is exactly what you want for production.
  • Terraform destroy or a resource replacement (delete then create) fails with ScopeLocked. Plan output that says "must be replaced" on a locked resource needs a deliberate decision, not a lock removal by reflex.
  • Manage locks themselves as code (Microsoft.Authorization/locks in Bicep, azurerm_management_lock in Terraform) so they can't silently disappear.

Quick triage table

Message or symptom Likely lock Action
ScopeLocked on delete CanNotDelete on resource, RG or subscription Confirm the delete is intended, then use the remove-change-recreate pattern
ScopeLocked on update/scale ReadOnly somewhere above Replace with CanNotDelete unless read-only is really required
Storage keys can't be listed ReadOnly Switch the app to Entra ID auth, or change the lock type
Backups failing with restore point errors CanNotDelete on the restore point resource group Move restore points to an unlocked resource group

Prevent it next time

  • Standardise: CanNotDelete on production resource groups, no ReadOnly on running workloads.
  • Put an owner and reason in every lock's --notes.
  • Report on locks monthly (az lock list across subscriptions) and compare against your expected list.
  • Use Azure Policy to audit production resource groups that have no lock.