Your Bicep deployment has run clean in dev for a week. You promote it to production, the pipeline kicks off, and forty seconds in it dies with QuotaExceeded: “Operation could not be completed as it results in exceeding approved standardDSv5Family Cores quota. Additional details - Current Limit: 10, Current Usage: 8, Additional Required: 8.” Nothing is wrong with your template. You have simply hit a quota — a per-subscription, per-region ceiling Azure puts on how much of a given resource you may create — and the default ceiling for that VM family in that region was lower than your production footprint. The fix is not a code change; it is a quota increase request, and if you know the path it takes ninety seconds and self-approves. If you don’t, you open a support ticket, wait, and ship late.
This article maps that territory. Azure lumps two different things under “limits,” and confusing them wastes hours. A quota (also called a service limit or usage limit) is an adjustable ceiling on a counted resource — vCPUs in a family, public IPs, storage accounts per region, network interfaces. You see your current usage against it and, for most, raise it. A hard limit is a fixed architectural boundary — max data disks on a VM size, the 65,536 addresses in a /16 VNet, subscriptions per tenant — that no asking moves; you design around it. Which kind you face is the entire difference between “file a request” and “re-architect.”
By the end you’ll read the usage-vs-limit numbers for any resource before they bite, in the portal and from az; tell an adjustable quota from a fixed limit on sight; request an increase three ways (the Azure Quotas experience, the az quota CLI, and as IaC) and know which requests auto-approve versus route to a human; and build a capacity-planning habit so the QuotaExceeded at 40 seconds into a production deploy becomes a number you checked last week, not a 2 a.m. surprise.
What problem this solves
Quotas exist for good reasons invisible until they cost you: Azure pre-allocates capacity per region and protects shared pools from a single subscription (or a runaway script, or a compromised credential) consuming everything. A fresh Pay-As-You-Go subscription doesn’t get unlimited cores on day one — often just ~10 total regional vCPUs plus small per-family allowances, raised as your footprint grows. The pain is purely informational: the limit is real, the usage is real, the gap is perfectly visible — but only if you look before the deployment, not after it fails.
What breaks without this knowledge is predictable and expensive. A team scales out for a launch and autoscale silently caps because the regional vCPU quota is exhausted — the site degrades not from a bug but because Azure refused instance number eleven. A DR failover fails because nobody ever requested quota in the secondary region. A Terraform apply of fifty resources rolls back halfway after tripping the public-IP quota on resource thirty-one. Each is a quota you could have read in advance.
Who hits this hardest: the people moving fast. New subscriptions hit it first (low defaults). Bursty workloads (batch, CI agents, flash-sale scale-out) hit vCPU and Spot quotas. Multi-region DR designs hit per-region quotas in the failover region. AKS node pools, VMSS and Azure Batch multiply vCPU consumption fast. And any CI/CD pipeline that creates real infrastructure hits it as a deployment failure — the worst time to discover a quota. The cure: treat quota like cost — monitor it and request ahead of need.
The spectrum runs from adjustable quotas (vCPUs per family, public IPs — raise on request, mostly automatic) through soft per-region caps (storage accounts, 250→500 via support) to fixed limits no request moves: hard platform (max data disks on a SKU → bigger SKU), hard architectural (65,536 IPs in a /16 → more VNets/peering), subscription-structural (~980 RGs → new subscription) and tenant-structural (subscriptions per EA → your account team). The next section sorts these into two buckets you can identify on sight.
Learning objectives
By the end of this article you can:
- Define quota, service limit and hard limit precisely, and tell which one you face from the error message alone.
- Read your current usage against the limit for vCPUs, public IPs, storage accounts and network resources — in the portal and with
az vm list-usage,az network list-usagesandaz quota list. - Navigate the Azure Quotas blade (My quotas), filter by provider and region, and read the usage bar for any quota.
- Request a quota increase three ways: the Quotas portal experience, the
az quota create/updateCLI, and as infrastructure-as-code — and predict which requests auto-approve versus route to support. - Distinguish per-subscription, per-region and per-resource-group scoping, and explain why a DR region needs its own quota.
- Identify the most common fixed limits (disks per VM, NICs per VM, IPs per VNet, RGs per subscription) so you design around them instead of filing doomed requests.
- Build a lightweight capacity-planning check — usage thresholds and alerts — so quota exhaustion becomes a number you watched, not a deploy that died.
Prerequisites & where this fits
You should already understand the Azure resource hierarchy: a management group contains subscriptions, a subscription contains resource groups, and resource groups contain resources. Quotas live almost entirely at the subscription + region level, so knowing what a subscription is — a billing and scope boundary — is the foundation. The Azure Resource Hierarchy Explained: Subscriptions, Resource Groups and Resources and Azure Subscriptions Explained: Types, Billing Boundaries and When to Create a New One give you that base.
You should be comfortable running az in Cloud Shell or a local terminal, reading JSON, and have at least Contributor (ideally a role with Microsoft.Support/* and Microsoft.Quota/*) on the subscription. You don’t need to know how to deploy the resources whose quota you’re reading — listing usage is read-only.
This sits in the Governance & Capacity Planning track, upstream of almost everything operational. It pairs with cost work — the Azure Cost Management for Beginners: Budgets, Alerts and Cost Analysis in Your First 30 Days habit is the same muscle pointed at money — and with Azure Support Plans Compared: Severity Levels, Response Times and What to Buy, since the human path for a large increase is a support request. Choosing VM sizes bumps straight into both quotas (vCPUs) and hard limits (disks per SKU), so Decoding Azure VM Series: Picking the Right D, E, F, L, N and M Family for Your Workload is a close neighbour.
Which layer owns which kind of limit, so you escalate right:
| Scope | What it counts | Typical owner | Example limit |
|---|---|---|---|
| Management group | Hierarchy depth/breadth | Platform / governance | MG depth (6 levels), MGs per tenant |
| Subscription | Resource groups, role assignments | Subscription owner | ~980 RGs; ~4,000 role assignments |
| Subscription + region | vCPUs, IPs, NICs, storage accts | App / platform team | vCPU family quotas; 250 storage accts |
| Resource | Disks, NICs, sub-resources | App team | Data disks per VM SKU; subnets per VNet |
| Tenant | Subscriptions, app registrations | Identity / account team | Subscriptions per EA; app regs |
Core concepts
Five ideas make every later step obvious.
A quota is usage-versus-limit, per subscription, per region. Every adjustable quota is two numbers: current usage (currentValue) and limit; the portal draws them as a bar. Both are scoped to one subscription in one region — westeurope and eastus vCPUs are entirely separate quotas. A request that raises one does nothing for the other, which explains most “but it worked in the other region” confusion.
vCPU quotas are layered: total regional, then per-family. Compute quota is not one number. There’s a Total Regional vCPUs limit for the whole region, and under it a per-VM-family limit (standardDSv5Family, standardFSv2Family, standardESv5Family). A deployment must satisfy both — you can have plenty of regional headroom and still fail because the specific family is capped. The error names the family precisely so you know which to raise. Spot vCPUs are a separate quota again, so heavy Spot use doesn’t eat your on-demand allowance.
Adjustable versus fixed is the first fork. Some ceilings are adjustable — you raise them by asking, mostly self-service. Others are fixed platform limits no request can move: max data disks on a VM size, NICs per SKU, the addressable space of a VNet CIDR, resource groups per subscription. When you hit a fixed limit the answer is never “request more” — it’s “choose a bigger SKU,” “split across more VNets,” or “use another subscription.”
The increase path forks on size and risk. Small routine bumps — a few more vCPUs in a family, a handful more public IPs — go through an automated approval system, often completing in seconds to minutes. Large jumps (hundreds of cores), constrained/new SKUs, GPU/HPC families, or capacity-pressured regions route to a human capacity team, taking hours to days. The Azure Quotas experience tries the automated path first and only falls back to a support request when it can’t self-approve.
Quotas are a capacity-planning input, not an incident. Treat quota like cost: a number you watch with a threshold, raise ahead of need, and request per region (especially the DR region). Azure surfaces usage for the major quotas as metrics, so you can alert at ~80% and request more before a launch — turning a deploy-time failure into a boring request done a week early.
The vocabulary in one table
Pin down the moving parts before the deep sections (the glossary repeats these for lookup):
| Term | One-line definition | Scope | Adjustable? |
|---|---|---|---|
| Quota | Adjustable ceiling on a counted resource | Subscription + region | Yes (mostly) |
| Service limit | Microsoft’s name for a quota (used in docs) | Varies | Yes if a quota |
| Hard limit | Fixed platform/architectural boundary | Resource / platform | No |
Usage (currentValue) |
How much of the quota you’ve consumed | Subscription + region | — |
Limit (limit) |
The ceiling you’re measured against | Subscription + region | Yes if a quota |
| Total Regional vCPUs | All-family vCPU ceiling for a region | Subscription + region | Yes |
| VM-family quota | vCPU ceiling for one family (e.g. DSv5) | Subscription + region | Yes |
| Spot vCPU quota | Separate ceiling for Spot instances | Subscription + region | Yes |
| Azure Quotas | The portal/API surface for viewing & raising | — | — |
| Quota request | The ask to raise a limit | Subscription + region | — |
| Auto-approval | Self-service grant for small/routine asks | — | — |
How Azure structures limits: quota vs hard limit
Before you read or raise anything, internalise the two buckets — the response to each is opposite.
Adjustable quotas — the things you can raise
An adjustable quota is a ceiling you can move on request — the numbers that scale with your footprint. The headline ones a typical team meets:
| Quota | Scope | Common default (PAYG) | Adjustable | How you raise it |
|---|---|---|---|---|
| Total Regional vCPUs | Subscription + region | ~10–20 (varies) | Yes | Azure Quotas / az quota |
Per-family vCPUs (e.g. standardDSv5Family) |
Subscription + region | Low per family | Yes | Azure Quotas / az quota |
| Spot vCPUs (total + per-family) | Subscription + region | Separate, often low | Yes | Azure Quotas |
| Standard public IP addresses | Subscription + region | Tens | Yes | Azure Quotas / support |
| Public IP prefixes | Subscription + region | Few | Yes | Support |
| Network interfaces | Subscription + region | Hundreds–thousands | Yes | Support |
| Network security groups | Subscription + region | ~5,000 | Yes (rarely needed) | Support |
| Load balancers | Subscription + region | ~1,000 | Yes | Support |
| Storage accounts per region | Subscription + region | 250 (raise to 500) | Yes | Support |
| App Service plans / instances | Subscription + region | Varies by tier | Partly | Support |
The defaults above are illustrative ranges, not promises — they vary by subscription type, region, offer and date. Always read your live value with the CLI in the next section. The point of the table is the shape: these are the levers you can pull.
Fixed limits — the things you design around
A fixed (hard) limit is structural — no request moves it; you change the design. The ones that bite teams most:
| Fixed limit | Approximate value | Why it’s fixed | What you do instead |
|---|---|---|---|
| Data disks per VM | 4–64 (by SKU) | Tied to the VM size’s I/O lanes | Pick a larger SKU; pool disks |
| NICs per VM | 2–8 (by SKU) | Tied to the VM size | Pick a larger SKU |
| Private IPs per NIC | ~256 | Platform | Add NICs / subnets |
| Subnets per VNet | ~3,000 | Platform | Fewer, bigger subnets |
| Addresses in a VNet | Defined by CIDR (e.g. /16 = 65,536) | IP math | Add address spaces / VNets + peering |
| VNet peerings per VNet | ~500 | Platform | Hub-spoke / mesh redesign |
| Resource groups per subscription | ~980 | Subscription structure | Split into more subscriptions |
| Resources per resource group | ~800 per type (varies) | Subscription structure | More RGs |
| Role assignments per subscription | ~4,000 | Identity platform | Use groups, not per-user |
| Management group depth | 6 levels | Hierarchy design | Flatten the tree |
| Subnets, NSG rules per NSG | ~1,000 rules | Platform | ASGs to collapse rules |
The tell for a fixed limit: it’s expressed as a maximum of a sub-resource per parent (disks per VM, subnets per VNet), or a structural cap (RGs per subscription). When you see that shape, there’s no “request increase” button. The decision rule:
| If the limit is expressed as… | It’s probably… | Your move |
|---|---|---|
| “X per region for your subscription” | An adjustable quota | Request an increase |
| “X cores of family Y” | An adjustable vCPU quota | Request more cores |
| “Maximum X per VM / VNet / NIC” | A fixed platform limit | Choose a bigger parent SKU/CIDR |
| “X per subscription” (RGs, role asgmts) | A structural limit | Split scope / new subscription |
| “X per tenant” (subscriptions, MGs) | A tenant-structural limit | Talk to your account/EA team |
Reading your usage before it bites
You cannot plan capacity you can’t see. Azure gives you the numbers in the portal, REST, and three CLI commands that cover 90% of what bites — get fluent in these and “surprise quota failure” mostly disappears.
vCPU usage with az vm list-usage
The single most useful quota command. It returns, for one region, every compute quota (total regional, every family, Spot) as currentValue vs limit:
# Every compute quota in a region: usage vs limit
az vm list-usage --location westeurope -o table
The output lists Total Regional vCPUs, Standard DSv5 Family vCPUs, etc., each with current/limit. To find what’s nearly full — the rows worth acting on — filter to where usage is a high fraction of the limit:
# Show only families where you're using > 80% of the limit
az vm list-usage --location westeurope --query \
"[?limit > \`0\` && currentValue >= (limit * \`0.8\` | floor(@))].{name:localName, used:currentValue, limit:limit}" \
-o table
Run it across the regions you actually deploy to, not just the one you live in:
for r in westeurope northeurope eastus; do
echo "== $r =="
az vm list-usage --location "$r" \
--query "[?localName=='Total Regional vCPUs'].{region:'$r', used:currentValue, limit:limit}" -o table
done
Network usage with az network list-usages
The network quotas — public IPs, NICs, NSGs, load balancers, VNets — come from a different command, also per region:
# Network quotas (public IPs, NICs, NSGs, LBs, VNets) usage vs limit
az network list-usages --location westeurope -o table
# Just public IP addresses, the one that bites bulk deploys
az network list-usages --location westeurope \
--query "[?contains(name.value,'PublicIPAddresses')].{name:name.localizedValue, used:currentValue, limit:limit}" \
-o table
Storage account usage with az storage account
Storage accounts are capped per region (commonly 250, raisable to 500). There’s no dedicated list-usage, so count what you have against the known cap:
# Count storage accounts in this subscription (all regions), then per region
az storage account list --query "length(@)"
az storage account list --query "[?location=='westeurope'] | length(@)"
The unified az quota surface
The newer az quota command group reads (and writes) quotas across providers through the Microsoft.Quota resource provider, using the provider scope of the thing you’re querying. For compute in a region:
SUB=$(az account show --query id -o tsv)
SCOPE="/subscriptions/$SUB/providers/Microsoft.Compute/locations/westeurope"
# List all compute quotas at this scope (usage + limit live behind quota + usages)
az quota list --scope "$SCOPE" -o table
# Current usage for the same scope
az quota usage list --scope "$SCOPE" -o table
# One specific quota by its resource name (e.g. total regional vCPUs)
az quota show --resource-name "cores" --scope "$SCOPE" -o json
The three commands you’ll actually reach for, side by side:
| Command | Covers | Scope it needs | Best for |
|---|---|---|---|
az vm list-usage --location <r> |
All compute (vCPU) quotas | A region | Daily vCPU headroom check |
az network list-usages --location <r> |
Public IPs, NICs, NSGs, LBs, VNets | A region | Network headroom before bulk deploy |
az quota list / usage list / show |
Any provider via Microsoft.Quota |
A provider+region scope | Programmatic / cross-provider reads and writes |
A reading note: currentValue is live consumption (changes as you create/delete resources); limit only changes when a request is granted. vCPU quota counts allocated cores — deallocated VMs hold none — but other resources (public IPs, NICs) count whether attached or not.
Requesting an increase: the three paths
When the gap is too small, you raise the ceiling. Three routes, picked by whether you’re a human at a portal, a script, or a platform team codifying it.
Path A — the Azure Quotas portal (the default)
The modern Azure Quotas experience (search “Quotas” in the portal, or the My quotas blade) is the path for most people most of the time. It tries the automated approval first and only escalates to a support request if it can’t self-approve. The flow:
| Step | Action | What you see |
|---|---|---|
| 1 | Open Quotas → choose a provider (e.g. Compute) | A grid of quotas with usage bars |
| 2 | Filter by subscription, region, usage | Narrowed list; sort by % used |
| 3 | Tick the quota row(s) you want to raise | A pencil / Increase quota action appears |
| 4 | Enter the new limit (absolute value, not delta) | A validation of feasibility |
| 5 | Submit | Auto-approved in seconds, or a support request is created |
| 6 | Watch status | Bar updates on approval; ticket if escalated |
Two traps: the value you enter is the new total limit, not the additional amount (typing 10 when you have 8 leaves you at 10, not 18). And pick the right region in the filter — the most common failed request raises eastus when production is in westeurope.
Path B — the az quota CLI (scriptable, repeatable)
For automation, runbooks or speed, create or update a quota request with az quota, setting the new absolute limit at the provider+region scope:
SUB=$(az account show --query id -o tsv)
SCOPE="/subscriptions/$SUB/providers/Microsoft.Compute/locations/westeurope"
# Raise the DSv5 family vCPU limit to 64 (new absolute value)
az quota create \
--resource-name "standardDSv5Family" \
--scope "$SCOPE" \
--limit-object value=64 \
--resource-type "dedicated"
# If a request already exists for that quota, update instead of create
az quota update \
--resource-name "standardDSv5Family" \
--scope "$SCOPE" \
--limit-object value=96
Track the request and read the outcome:
# Status of submitted quota requests at this scope
az quota request status list --scope "$SCOPE" -o table
# Detail of one request (Accepted / InProgress / Succeeded / Failed)
az quota request status show --name <requestId> --scope "$SCOPE" -o json
The --resource-name is the quota’s internal name, not its display name — standardDSv5Family, cores (for total regional), standardFSv2Family, etc. Read it from az quota list --scope "$SCOPE" first if unsure; guessing the name is the usual cause of a create that 400s.
Path C — a support request (the human path for big asks)
When the automated path can’t self-approve — large core counts, constrained/GPU SKUs, capacity-pressured regions, or non-vCPU quotas that route to humans — you file a Service and subscription limits (quotas) support request. Also the path if you want a ticket trail. From the Quotas blade’s escalation, or directly:
# Open a quota-type support ticket (requires a support plan for faster SLA)
az support tickets create \
--ticket-name "quota-dsv5-westeurope-2026-06" \
--title "Increase DSv5 vCPU quota in West Europe to 256" \
--severity "minimal" \
--problem-classification "<quota-problem-classification-id>" \
--quota-ticket-details '{"quotaChangeRequestSubType":"Compute","quotaChangeRequestVersion":"1.0","quotaChangeRequests":[{"region":"westeurope","payload":"{\"VMFamily\":\"standardDSv5Family\",\"NewLimit\":256}"}]}'
The SLA on a quota ticket depends on your support plan and the severity you set — see Azure Support Plans Compared: Severity Levels, Response Times and What to Buy. Quota requests are typically low/minimal severity — you’re not down, you’re planning ahead — so set severity honestly.
Which path, when
| Situation | Use | Why |
|---|---|---|
| Routine vCPU/IP bump, you’re at a portal | Quotas portal (A) | Auto-approves in seconds |
| Same bump, but in a pipeline/runbook | az quota (B) |
Scriptable, idempotent-ish, auditable |
| Hundreds of cores / GPU / constrained SKU | Support request © | Needs human capacity allocation |
| Quota with no self-service (some net/storage) | Support request © | Routes to capacity team |
| Codifying baseline quotas for new subs | az quota in IaC/pipeline (B) |
Repeatable landing-zone step |
| You want a paper trail / SLA | Support request © | Ticket with tracked SLA |
Will it auto-approve? The mental model
You can predict the path before you submit:
| Factor | Leans auto-approve | Leans human review |
|---|---|---|
| Magnitude | Small delta (e.g. +8–32 cores) | Large jump (hundreds of cores) |
| SKU type | Common GP family (Dsv5, etc.) | GPU / HPC / specialty / constrained |
| Region capacity | Healthy region | Capacity-pressured region |
| Resource kind | vCPU, public IP | Some networking/storage/PaaS |
| Current usage | Plenty of regional headroom | Pushing total regional limit too |
| Account standing | Established billing history | Brand-new / trial subscription |
The takeaway: ask early and in modest steps and the system mostly says yes instantly. Ask for a 20× jump the night before launch in a hot region and you’ve signed up for a human, a queue and a wait.
Scope: per-subscription, per-region, per-resource-group
Most quota confusion is a scope mistake. Three rules end it.
vCPU and network quotas are per subscription AND per region. Your 200-core westeurope quota grants nothing in northeurope. When you design multi-region — active-active or a DR secondary — request quota in every region you’ll deploy to, including the one you only fail over to. A failover that can’t allocate cores because the secondary region was never quota-provisioned is a classic, avoidable DR-test failure. (See Azure Regions and Availability Zones: Designing for Resilience.)
Some limits are per subscription, region-agnostic. Resource groups (~980), role assignments (~4,000), and structural caps count across the whole subscription. You don’t “request more eastus resource groups”; you stay under the cap or split into another subscription.
A few limits are per resource group or per resource. Resources of one type per RG, sub-resources per parent (subnets per VNet, disks per VM). These you manage by structure, not request.
| Limit | Per subscription? | Per region? | Per RG / resource? |
|---|---|---|---|
| vCPUs (total + family) | Yes | Yes | No |
| Public IPs, NICs, NSGs | Yes | Yes | No |
| Storage accounts | Yes | Yes | No |
| Resource groups | Yes | No | No |
| Role assignments | Yes | No | No |
| Subnets per VNet | No | No | Per VNet |
| Data disks per VM | No | No | Per VM |
The operational rule that falls out: inventory the regions in your architecture, then run the usage check in each one. A one-region audit on a multi-region design is false comfort.
Architecture at a glance
Hold this mental model and quotas stop being mysterious. Picture three nested rings. The outermost is the tenant, where a few truly structural limits live (how many subscriptions, how deep the management-group tree goes) — set by your Microsoft agreement and governance design, moving rarely if ever. Inside it sit your subscriptions, each a billing-and-scope boundary carrying the region-agnostic structural caps: resource groups, role assignments, resources of a kind. These you manage by splitting — when one fills up, the answer is another subscription, not a request.
Zoom into a subscription and it fans out into regions — this is where the quotas you fight with live. For each region the subscription holds an independent set of meters: a Total Regional vCPU ceiling, a stack of per-family vCPU ceilings beneath it, a separate Spot stack, and the network meters (public IPs, NICs, NSGs, load balancers) — every one a currentValue/limit pair specific to this subscription in this region. Finally, inside each region, individual resources carry their own fixed sub-limits: a VM’s disk and NIC ceilings, a VNet’s subnet and peering ceilings, baked into the SKU or CIDR.
Read a deployment failure by walking inward. QuotaExceeded naming a vCPU family? The region ring — adjustable, request more in that region. “Maximum data disks” or “subnets per VNet”? The innermost resource ring — fixed, change the parent. “Resource groups per subscription”? The subscription ring — structural, split scope. The error tells you which ring you’re in; the ring tells you whether to file a request or redesign. This nested-rings picture is the model — more useful in your head than drawn on a page.
Real-world scenario
Northwind Retail runs e-commerce out of westeurope, with DR in northeurope. Steady-state they run ~120 vCPUs across Dsv5 web/API tiers and Esv5 workers, inside a regional quota raised to 256 cores a year earlier. Two things were about to collide: a Black Friday scale-out to ~400 vCPUs at peak, and a long-scheduled DR failover test the same quarter.
The first warning came from a habit, not an incident. Platform engineer Sana ran the weekly headroom check — a scheduled pipeline doing az vm list-usage across both regions, flagging anything over 70% — and westeurope Dsv5 showed 198 / 256, climbing as they pre-staged. At 77% the flag fired. Six weeks out, with no outage, she raised westeurope total regional vCPUs and standardDSv5Family to 512 via az quota update. Both auto-approved within two minutes — modest steps on an established subscription, common GP family, healthy region. No ticket, no wait.
The DR region is where the lesson landed. The same audit script ran against northeurope and reported standardDSv5Family: 0 / 10. They had never requested compute quota in the failover region — every deploy had only ever touched westeurope. Had the failover test run, it would have tried to stand up ~120 cores of Dsv5 and hit QuotaExceeded at core eleven, failing the DR test not because of replication or DNS but because the secondary region had a default quota. Sana requested northeurope to match the primary’s steady-state plus burst — 512 cores. This one did not auto-approve: a 50× jump on a region with zero history routed to a support request, severity minimal, granted in about a day on their Standard support plan. Because it was raised six weeks early, the wait was invisible.
Black Friday came. Autoscale took the web tier from 120 to 390 vCPUs at peak; every scale-out succeeded because the ceiling was 512 with room to spare. The mid-quarter DR test failed over to northeurope, allocated its full footprint, and passed. The total cost of avoiding two embarrassing failures: one scheduled az vm list-usage pipeline, two requests filed weeks early, and the discipline to check both regions. The fix was never technical; it was temporal. They looked early.
Advantages and disadvantages
Quotas are a feature, not just an obstacle — they protect you as much as they constrain you.
| Quotas (the system) | What it means for you | |
|---|---|---|
| Advantage | Cap blast radius of a bug/compromise | A runaway script or leaked credential can’t spin up unlimited resources |
| Advantage | Protect shared regional capacity | Your deploy isn’t starved because another tenant grabbed everything |
| Advantage | Force capacity planning | You’re nudged to think about footprint before you hit the wall |
| Advantage | Cost guardrail (indirect) | A low vCPU quota is a soft brake on runaway compute spend |
| Advantage | Auto-approval makes routine asks instant | Small bumps don’t slow you down |
| Disadvantage | Deploy-time failures if unplanned | QuotaExceeded mid-pipeline leaves half-built infra |
| Disadvantage | Per-region scoping is a footgun | Easy to forget the DR region and fail a failover |
| Disadvantage | Big asks need humans + time | Hundreds of cores in a hot region can take days |
| Disadvantage | Defaults are low for new subscriptions | First real deploy on a fresh sub often hits the wall |
| Disadvantage | Fixed limits can force a redesign | Some “limits” can’t be raised at all — only architected around |
The advantages matter most to platform and security teams: a cheap, automatic guardrail against worst-case spend or compromise, costing nothing to keep. The disadvantages matter most to delivery teams under time pressure: treat quota as a deploy-time discovery and it’s pure friction, and the per-region footgun will eventually bite a DR test. The whole art is converting the disadvantages into non-events by adopting the advantage-side mindset — plan capacity, watch usage, request early, per region.
Hands-on lab
The centerpiece. You’ll read your quotas end to end in the portal and with az, request an increase via the CLI, encode a usage-alert with Bicep, and tear down — all read-only or low-cost, safe on any subscription. Most steps cost nothing (reads and a metric alert are effectively free; the one optional VM is pennies and you delete it). Expected output is shown at each step so you can validate as you go.
Prerequisites for the lab:
| Requirement | Why | Check |
|---|---|---|
| An Azure subscription | Everything is per-subscription | az account show |
az ≥ 2.50 with the quota extension |
az quota lives in an extension |
az version; az extension add --name quota |
| Reader (to read) / Contributor+ (to request) | Reads need Reader; requests need write | az role assignment list --assignee <you> |
| A region you deploy to (pick one) | Quotas are per-region | choose e.g. westeurope |
| Cloud Shell or local terminal logged in | To run az |
az login |
Step 0 — Set up and pin your context
# Log in (skip in Cloud Shell) and pin the subscription + region you'll use
az login
az account set --subscription "<your-subscription-id-or-name>"
# Variables we'll reuse
SUB=$(az account show --query id -o tsv)
LOC="westeurope"
echo "Subscription: $SUB Region: $LOC"
# Ensure the quota CLI extension is present
az extension add --name quota --only-show-errors || az extension update --name quota
Expected output: your subscription id and chosen region echoed; the extension installs or reports already-installed. If az account show errors, you’re not logged in.
Step 1 — Read vCPU usage in the portal
- In the portal, search Quotas and open it.
- Choose the Compute provider tile (or My quotas → filter Provider = Microsoft.Compute).
- Set Subscription to yours and Region to your chosen region.
- Sort by Usage descending.
Expected output: a grid of compute quotas, each with a usage bar showing current vs limit. Note the row Total Regional vCPUs and your most-used family (e.g. Standard DSv5 Family vCPUs). On a quiet subscription many bars are near-empty — that’s fine; you’re learning to read them.
Validate: you can point to one quota and say “I’m using N of M here.” No usage bar? You’re probably on the old “Usage + quotas” blade — use the dedicated Quotas service instead.
Step 2 — Read the same numbers from the CLI
# Full compute quota table for your region
az vm list-usage --location "$LOC" -o table
Expected output: rows like:
Name CurrentValue Limit
---------------------------- -------------- -------
Total Regional vCPUs 0 10
Standard DSv5 Family vCPUs 0 10
Standard FSv2 Family vCPUs 0 10
...
Now isolate the high-usage rows you’d actually act on:
az vm list-usage --location "$LOC" --query \
"[?limit > \`0\` && currentValue >= (limit * \`0.5\` | floor(@))].{name:localName, used:currentValue, limit:limit}" \
-o table
Expected output: only families at ≥50% (often empty on a quiet sub — a valid result meaning lots of headroom). Lower the 0.5 to surface more rows for practice.
Validate: the portal numbers from Step 1 match the CLI numbers for the same region — same source, identical values.
Step 3 — Read network and storage usage
# Network quotas (public IPs, NICs, NSGs, LBs, VNets)
az network list-usages --location "$LOC" -o table
# Public IP line specifically
az network list-usages --location "$LOC" \
--query "[?contains(name.value,'PublicIPAddresses')].{name:name.localizedValue, used:currentValue, limit:limit}" -o table
# Storage accounts: count vs the per-region cap
az storage account list --query "[?location=='$LOC'] | length(@)"
Expected output: a network usage table; a single public-IP row (e.g. Public IP Addresses 0 <limit>); and a storage-account count for the region (often 0 on a fresh sub) — you’re validating you’re well under the 250→500 cap.
Validate: you now have, for one region, vCPU + network + storage headroom in three commands. That’s the daily check.
Step 4 — Use the unified az quota surface
SCOPE="/subscriptions/$SUB/providers/Microsoft.Compute/locations/$LOC"
# All compute quotas via the Quota RP
az quota list --scope "$SCOPE" -o table
# Live usage at the same scope
az quota usage list --scope "$SCOPE" -o table
# One specific quota by internal name — total regional vCPUs is "cores"
az quota show --resource-name "cores" --scope "$SCOPE" -o json \
--query "{name:name, limit:properties.limit.value, unit:properties.unit}"
Expected output: quota list returns quotas with their internal resource names (cores, standardDSv5Family, …) — note these; you need the exact name to request a change. quota show for cores returns a small JSON with the limit value.
Validate: you can map a display name (“Total Regional vCPUs”) to its internal name (cores) — the mapping most failed CLI requests get wrong.
Step 5 — Request a quota increase via CLI (small, auto-approvable)
Pick a quota with plenty of headroom and request a modest bump so it’s likely to auto-approve and costs nothing (raising a limit creates no resources). We’ll nudge a family’s vCPU limit up slightly.
SCOPE="/subscriptions/$SUB/providers/Microsoft.Compute/locations/$LOC"
# Read the current limit for the family first (so you set a sane new absolute value)
CUR=$(az quota show --resource-name "standardDSv5Family" --scope "$SCOPE" \
--query "properties.limit.value" -o tsv)
echo "Current DSv5 limit: $CUR"
# Request a new ABSOLUTE limit a bit higher (e.g. current + 10, capped low to stay auto-approvable)
NEW=$(( CUR + 10 ))
az quota create \
--resource-name "standardDSv5Family" \
--scope "$SCOPE" \
--limit-object value=$NEW \
--resource-type "dedicated" \
|| az quota update --resource-name "standardDSv5Family" --scope "$SCOPE" --limit-object value=$NEW
Expected output: a JSON request object with provisioningState of Accepted, InProgress, or Succeeded. Small bumps on healthy regions frequently flip to Succeeded within a minute or two. Track it:
az quota request status list --scope "$SCOPE" \
--query "[].{name:name, state:properties.provisioningState, created:properties.requestSubmitTime}" -o table
Expected output: your request with a state column. Succeeded = granted; InProgress = still deciding; Failed = read properties.message (most often a bad resource-name or an over-large jump routed to humans).
Validate: re-run Step 4’s az quota show for standardDSv5Family. If granted, the limit now reflects $NEW. Still pending is a valid outcome too — you’ve submitted a request, which is the skill.
If your org restricts quota changes, this step may be denied by policy — that’s expected. The objective is knowing the command and reading the status; you can stop after
request status list.
Step 6 — Alert before you exhaust: a usage metric alert in Bicep
Turn quota into a watched number. Azure exposes compute quota usage as a metric you can alert on. Here’s a metric alert (the free tier covers a few alert rules) that fires when regional vCPU usage crosses a threshold. Save as quota-alert.bicep:
@description('Region whose vCPU usage we watch')
param location string = 'westeurope'
@description('Action group to notify (create or reference an existing one)')
param actionGroupId string
@description('Fire when this many vCPUs are in use in the region')
param vcpuThreshold int = 200
// Quota usage is published under the subscription/region as a metric on the
// Microsoft.Capacity/resourceProviders usages namespace. We alert on it.
resource quotaAlert 'Microsoft.Insights/metricAlerts@2018-03-01' = {
name: 'alert-regional-vcpu-usage-${location}'
location: 'global'
properties: {
description: 'Warn when regional vCPU usage approaches the quota limit'
severity: 2
enabled: true
scopes: [
subscription().id
]
evaluationFrequency: 'PT15M'
windowSize: 'PT1H'
targetResourceType: 'Microsoft.Compute/locations/usages'
targetResourceRegion: location
criteria: {
'odata.type': 'Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria'
allOf: [
{
name: 'TotalRegionalvCPUs'
metricNamespace: 'Microsoft.Compute/locations/usages'
metricName: 'Usage'
operator: 'GreaterThan'
threshold: vcpuThreshold
timeAggregation: 'Maximum'
criterionType: 'StaticThresholdCriterion'
}
]
}
actions: [
{
actionGroupId: actionGroupId
}
]
}
}
output alertName string = quotaAlert.name
Deploy it (you need an action group id — reuse one from your cost/monitor alerts; see How to Create Your First Metric Alert and Action Group for Email, SMS and Push):
# Validate first (preflight), then deploy at subscription scope
AG_ID=$(az monitor action-group show -n <your-action-group> -g <rg> --query id -o tsv)
az deployment sub validate \
--location "$LOC" \
--template-file quota-alert.bicep \
--parameters location="$LOC" actionGroupId="$AG_ID" vcpuThreshold=200
az deployment sub create \
--location "$LOC" \
--template-file quota-alert.bicep \
--parameters location="$LOC" actionGroupId="$AG_ID" vcpuThreshold=200
Expected output: validate returns no errors; create returns Succeeded and the alert name. The alert now sits at subscription scope and evaluates regional vCPU usage hourly.
Validate: Monitor → Alerts → Alert rules shows alert-regional-vcpu-usage-westeurope, enabled. You’ve converted “quota” into “monitored capacity.”
The exact metric namespace/name for quota usage can differ by provider and evolve; if the alert won’t validate, list metrics for the usage resource with
az monitor metrics list-definitions --resource <usage-resource-id>and match the realmetricName. The pattern — alert on usage, fire before the limit — is the durable lesson.
Step 7 — (Optional) Make usage move, then watch it
To see currentValue change, create one tiny VM, re-read usage, then delete it — a few pennies for minutes of runtime, so delete promptly.
RG="rg-quota-lab"
az group create -n "$RG" -l "$LOC"
# Before: note DSv5 usage
az vm list-usage --location "$LOC" \
--query "[?contains(localName,'DSv5')].{name:localName, used:currentValue, limit:limit}" -o table
# Create one small Dsv5 VM (2 vCPUs) — this consumes vCPU quota while allocated
az vm create -g "$RG" -n vm-quota-lab \
--image Ubuntu2204 --size Standard_D2s_v5 \
--admin-username azureuser --generate-ssh-keys --no-wait
# Give it ~60–90s to allocate, then re-read (usage should rise by 2)
az vm list-usage --location "$LOC" \
--query "[?contains(localName,'DSv5')].{name:localName, used:currentValue, limit:limit}" -o table
Expected output: the used value for the DSv5 family increases by 2 (the D2s_v5’s vCPUs) once allocated — quota consumption you can see.
Validate: the DSv5 bar in the portal (Step 1) nudges up too. You’ve watched usage rise toward a limit in real time.
Step 8 — Teardown
# Delete the optional VM + its RG (releases the 2 vCPUs of quota)
az group delete -n "$RG" --yes --no-wait
# Delete the metric alert if you don't want to keep it
az monitor metrics alert delete -n "alert-regional-vcpu-usage-${LOC}" -g <rg-where-deployed> 2>/dev/null || \
az deployment sub create --location "$LOC" --template-file /dev/stdin <<< '{}' 2>/dev/null
Expected output: the resource group deletes (vCPU usage returns to its prior value within a minute or two); the alert is removed. The quota increase from Step 5 stays — limits don’t auto-revert and a higher limit costs nothing, so there’s no need to undo it.
Validate: az vm list-usage --location "$LOC" shows DSv5 currentValue back where it started; the lab alert is gone. You’ve completed a full read → request → alert → teardown cycle.
A recap of what each step proved:
| Step | You learned to… | Cost |
|---|---|---|
| 0–1 | Pin context; read quotas with the portal usage bar | Free |
| 2–3 | Read vCPU, network, storage usage from az |
Free |
| 4 | Map display names → internal names via az quota |
Free |
| 5 | Submit and track a quota increase request | Free |
| 6 | Alert before exhaustion with Bicep | Free (alert rule) |
| 7 | Watch usage rise against a limit in real time | Pennies (deleted) |
| 8 | Tear down cleanly; know what persists | Free |
Common mistakes & troubleshooting
The failure modes here are mostly conceptual — wrong scope, wrong number, wrong kind of limit — each with a precise tell and fix.
| # | Symptom | Root cause | How to confirm | Fix |
|---|---|---|---|---|
| 1 | QuotaExceeded for a VM family mid-deploy |
Family vCPU limit too low in this region | Error text names family + “Current Limit”; az vm list-usage |
Request that family’s quota up in this region |
| 2 | Increase request “did nothing” | Entered a delta as the new limit | Compare requested value to old limit | Re-request the absolute target (old + needed) |
| 3 | Request rejected / routed to support unexpectedly | Big jump / GPU / constrained SKU / hot region | az quota request status show message |
File a support request; ask in smaller steps |
| 4 | Plenty of total cores but still fails | Per-family quota exhausted under the regional total | az vm list-usage shows family near limit |
Raise the family quota, not just total |
| 5 | Worked in region A, fails in region B | Quotas are per region; B never raised | Run az vm list-usage in B |
Request the same quota in region B |
| 6 | DR failover can’t allocate compute | DR region on default quota | az vm list-usage --location <dr> shows low limit |
Pre-provision quota in the DR region |
| 7 | Autoscale stops adding instances | Hit regional/family vCPU ceiling | Plan instance count flat; usage at limit | Raise vCPU quota; or use a smaller SKU |
| 8 | “Max data disks” / “max NICs” error | Fixed SKU limit, not a quota | Docs/error say “per VM” | Choose a larger VM SKU — no request exists |
| 9 | Can’t add another resource group | Hit ~980 RGs per subscription | az group list --query "length(@)" |
Split into a new subscription |
| 10 | az quota create returns 400 |
Wrong internal resource name | az quota list --scope ... shows real names |
Use the exact internal name (cores, standardDSv5Family) |
| 11 | Spot deploy fails though on-demand quota is fine | Spot vCPUs are a separate quota | az vm list-usage shows Spot rows |
Raise the Spot vCPU quota specifically |
| 12 | Bulk Terraform apply rolls back partway | Tripped public-IP/NIC quota mid-run | az network list-usages; check failed resource |
Raise the network quota; or stagger the apply |
Three of these deserve a closer note:
- The
QuotaExceededdeploy failure (1). Read the message literally — “…standardDSv5Family Cores quota. Current Limit: 10, Current Usage: 8, Additional Required: 8” gives the family, ceiling (10), usage (8) and need (→16, over 10). The fix is arithmetic: request the family to ≥16, ideally 32. Confirm the region from the deployment — the same template againsteastusnames the same family but a different region’s quota. - The per-region trap (5/6). The most expensive mistake, surfacing during a DR test or regional expansion: every
az vm list-usageand every quota request is region-scoped, and a subscription’s regions are independent. The cure is procedural — list every region in your architecture and run the headroom check against all of them on a schedule, requesting in each. - When there’s no button (8/9). When the limit is fixed, stop troubleshooting the quota and change the design. “Max data disks per VM” → move to a bigger SKU. “RGs per subscription” → the Azure Subscriptions Explained: Types, Billing Boundaries and When to Create a New One decision applies. A support request here returns “this is a hard limit” and a lost day.
Best practices
- Read quotas before you deploy, not after. Make
az vm list-usage/az network list-usagesa pre-flight step in your pipeline or runbook for any sizeable provisioning. A failed deploy from quota is always preventable. - Audit every region in your architecture. Primary, DR and any expansion region each get the scheduled headroom check — the per-region footgun only bites teams who check one region.
- Request early and in modest steps. Small bumps on an established subscription auto-approve in minutes; stair-step up your growth curve instead of asking for a 20× jump under deadline.
- Enter absolute limits, not deltas. Both the portal and
az quotawant the new total — compute old + needed + headroom and request that number. - Raise the family AND the regional total. A deploy must satisfy both; raising only one leaves the other as the bottleneck.
- Pre-provision the DR region’s quota. Before any failover test, ensure the secondary region can allocate your full footprint.
- Know the fixed limits for your SKUs upfront. Disks-per-VM, NICs-per-VM, IPs-per-VNet — design with these in mind so you never file a doomed request.
- Alert on usage, not just on failure. Wire a metric alert at ~70–80% of a critical quota — same discipline as a cost budget.
- Use the right path for the size. Auto-approve for routine bumps, support request for big/constrained/GPU asks — don’t over-escalate the small or under-plan the large.
- Codify baseline quotas in your landing zone. When you stamp a new subscription, raise the quotas you know you’ll need so it doesn’t ship with day-one defaults.
- Keep Spot and on-demand quotas separate in your head. Heavy Spot use needs its own requests; on-demand headroom doesn’t cover it.
- Match your support plan to your quota cadence. If big asks are routine, a faster-SLA plan pays for itself the first time a launch depends on a same-day grant.
Security notes
Quotas are themselves a security control, and managing them touches identity. A low default vCPU quota is a built-in brake on a compromised credential or runaway automation — an attacker (or a buggy loop) trying to spin up a crypto-mining fleet hits your ceiling fast — so don’t reflexively max out every quota; leave them sized to real need plus reasonable headroom so the ceiling stays meaningful.
Changing a quota or opening a quota ticket is privileged: grant Microsoft.Quota/* and Microsoft.Support/* narrowly (platform/SRE, not every Contributor), so a developer can read usage with Reader but only a platform role can request increases — and scope the monitoring identity that runs the scheduled check to Reader only. (See Azure Policy Effects Explained: Deny, Audit, Modify and DeployIfNotExists for codifying such guardrails.) A sudden increase can signal misuse, so collect Microsoft.Quota and support-ticket operations from the Activity Log to keep increases traceable to a person and a justification.
| Concern | Control | How |
|---|---|---|
| Runaway/compromise blast radius | Keep quotas sized to need | Don’t max everything; review headroom |
| Who can raise quotas | RBAC least privilege | Limit Microsoft.Quota/* + support roles to platform team |
| Read access for monitoring | Reader-only identity | Scope the headroom-check principal to Reader |
| Traceability | Activity Log / audit | Collect Microsoft.Quota + support ops to a workspace |
Cost & sizing
The reassuring part: raising a quota costs nothing. A quota is a ceiling, not a reservation — you’re billed for resources you create, never for headroom you don’t use. A 1,000-core quota with 50 cores running costs exactly the same as a 100-core quota with 50 cores running.
The cost relationship is indirect, two ways. A quota is a soft spending brake: a low vCPU quota means a runaway autoscale can only spend so much before hitting the wall — which is why you don’t max out quotas you don’t need. And the real cost lives in the resources you provision up to the quota, so when you plan an increase you’re implicitly planning the spend that fills it — pair the request with a budget (Azure Cost Management for Beginners: Budgets, Alerts and Cost Analysis in Your First 30 Days) and a look at Azure Advisor for Cost: Acting on Rightsizing and Idle-Resource Recommendations so the cores you unlock are right-sized.
What drives the bill behind a vCPU quota, in rough INR/USD orders of magnitude (varies — always price your real SKU):
| Driver | Rough cost order | Notes |
|---|---|---|
| The quota itself | ₹0 / $0 | Ceilings are free; you pay for usage |
| On-demand vCPU (e.g. D2s_v5, 2 vCPU) | ~₹7–10k / ~$85–120 per month if always on | Per-second billed; deallocate to stop |
| Spot vCPU | Up to ~90% cheaper than on-demand | Separate quota; can be evicted |
| Public IP (Standard) | ~₹250–400 / ~$3–5 per IP/month | Counts against IP quota whether attached or not |
| Storage account | Pennies + per-GB/transaction | Account is cheap; data/ops drive cost |
| The metric alert from the lab | Free–negligible | A few alert rules are free; high volume is cents |
The free-tier angle: Free/Trial and fresh PAYG subscriptions start with low quotas by design (often ~10 total regional vCPUs), so your first real workload almost always needs a bump — budget a few minutes for it in onboarding. Right-sizing rule of thumb: request steady-state + planned burst + ~20–30% headroom, not a round-number maximum — a wildly oversized quota is a wider blast radius for zero saving, while a too-tight one fails your next scale-out.
Interview & exam questions
Q1. What is the difference between an Azure quota and a hard limit? A quota (service/usage limit) is an adjustable ceiling on a counted resource — vCPUs, public IPs, storage accounts — you can raise on request, often self-service. A hard limit is a fixed boundary — data disks per VM SKU, addresses in a VNet CIDR, RGs per subscription — that no request changes; you design around it. Telling them apart from the error is the key skill. Relevant to AZ-104 and AZ-305.
Q2. A deployment fails with QuotaExceeded for standardDSv5Family. Walk through your response.
Read the error for family, current limit, usage and additional-required. Confirm with az vm list-usage --location <region>. Request that family’s quota to the needed total plus headroom, in that region, via the Quotas portal or az quota create/update with an absolute value. Verify and re-run the deploy.
Q3. Why might a deployment fail on vCPU quota even though “Total Regional vCPUs” has headroom? vCPU quota is layered: a regional total and a per-family limit beneath it, and a deployment must satisfy both. The family (e.g. DSv5) can be exhausted while the regional total still has room. Fix by raising the family quota, not just the total.
Q4. Your DR failover test fails to allocate compute in the secondary region. Why, and how do you prevent it?
Quotas are per region, and the DR region was never quota-provisioned — it sits on default low limits. Treat quota as part of DR readiness: pre-request the full failover footprint in the secondary region and verify with az vm list-usage --location <dr-region> before the test.
Q5. Which quota requests auto-approve, and which need a human? Small routine bumps (a modest number of vCPUs in a common GP family, a few public IPs) on established subscriptions in healthy regions usually auto-approve in seconds to minutes. Large jumps (hundreds of cores), GPU/HPC/constrained SKUs, capacity-pressured regions, and some networking/storage quotas route to a human capacity team and take longer.
Q6. What scoping applies to vCPU quotas versus resource-group limits? vCPU and most network quotas are scoped to subscription + region — independent per region. The RGs-per-subscription limit (~980) is per subscription, region-agnostic. Raising one region’s vCPU quota does nothing for another; the RG cap is solved by a new subscription, not a request.
Q7. How do you read current usage against a quota from the CLI?
az vm list-usage --location <region> for compute (returns currentValue vs limit per family and the regional total); az network list-usages --location <region> for public IPs/NICs/NSGs/LBs; and az quota list/usage list/show --scope <provider+region> for a unified, cross-provider view including the internal resource names needed to request changes.
Q8. Does raising a quota cost money? No. A quota is a ceiling, not a reservation — you’re billed only for resources you create. A higher quota with the same running resources costs the same. The cost is indirect (a higher quota enables more spend), so pair increases with budgets and right-sizing.
Q9. You hit “maximum data disks” on a VM. Do you request a quota increase? No — that’s a fixed limit tied to the VM SKU, not a quota. There’s no increase to request. Move to a larger size that supports more data disks, or restructure storage (fewer, larger disks).
Q10. Why are Spot vCPUs sometimes a separate problem from on-demand? Spot has its own vCPU quota (total regional + per-family Spot), distinct from on-demand. A subscription can have ample on-demand headroom but a near-zero Spot quota, so a Spot batch/build fleet fails while regular VMs deploy fine. Raise the Spot quota specifically.
Q11. What’s the recommended way to avoid quota-driven deploy failures operationally?
Make a per-region usage check (az vm list-usage / az network list-usages) a scheduled job and pipeline pre-flight, alert at ~70–80% of critical quotas, and request increases ahead of need in every region you deploy to.
Q12. How does your support plan relate to quota increases? Routine bumps go through automated self-service regardless of plan. A large ask that routes to a support request has an SLA driven by your support plan and severity. If same-day large grants matter to your launches, a faster-SLA plan is the enabler.
Quick check
- You enter
10as the new limit for a family currently at limit8and you needed8more. What did you just do wrong, and what should you have entered? az vm list-usageshows Total Regional vCPUs at40/256but your DSv5 deploy still fails on quota. What’s the cause and the fix?- Name three things that are fixed limits (no increase possible) and what you do instead for each.
- Your app runs fine in
westeuropebut the DR deploy innortheuropefails to allocate cores. Why? - Which CLI command shows public-IP usage against its limit, and at what scope?
Answers
- You set the new absolute limit to 10 (only +2), not the +8 you needed — the field is an absolute total, not a delta. You should have entered 16 (current 8 + needed 8), ideally 32 for headroom.
- The per-family DSv5 quota is exhausted even though the regional total has room — both must be satisfied. Fix: request the
standardDSv5Familyquota up inwesteurope(not just the regional total). - Examples: data disks per VM (→ choose a larger SKU), addresses in a VNet
/16(→ add address space / more VNets + peering), resource groups per subscription ~980 (→ new subscription). All are structural; no request applies. - Quotas are per region;
northeuropewas never quota-provisioned and sits on default low limits. Request the DSv5/regional quota innortheuropeand verify withaz vm list-usage --location northeurope. az network list-usages --location <region>(filter forPublicIPAddresses) — scope is subscription + region.
Glossary
- Quota — An adjustable per-subscription, per-region ceiling on a counted resource (vCPUs, public IPs, storage accounts). Raise on request.
- Service limit / usage limit — Microsoft’s documentation terms for a quota; the adjustable ones are the same thing as a quota.
- Hard limit — A fixed platform or architectural boundary (disks per VM SKU, IPs in a CIDR, RGs per subscription) that no request can change; you design around it.
- Usage (
currentValue) — Live consumption of a quota; rises and falls as you create and delete resources. - Limit (
limit) — The ceiling you’re measured against; changes only when a quota request is granted. - Total Regional vCPUs — The all-family vCPU ceiling for a subscription in one region; internal name
cores. - VM-family quota — The vCPU ceiling for one VM family (e.g.
standardDSv5Family) under the regional total; both must be satisfied. - Spot vCPU quota — A separate vCPU ceiling for Spot instances (total regional + per-family), distinct from on-demand.
- Azure Quotas — The portal/API/CLI surface (
Microsoft.Quota) for viewing usage and requesting increases; the My quotas blade. - Quota request — The submitted ask to raise a limit; tracked via
az quota request statuswith states like Accepted/InProgress/Succeeded/Failed. - Auto-approval — The automated self-service grant for small/routine requests, often completing in seconds to minutes.
- Support request (quota type) — The human path for large/constrained/GPU asks; SLA depends on your support plan and severity.
- Scope (quota) — The subscription + provider + region a quota applies to; e.g.
/subscriptions/<id>/providers/Microsoft.Compute/locations/westeurope. - Per-region scoping — The rule that vCPU/network quotas are independent per region; the source of most “worked in the other region” confusion.
Next steps
- Ground the scoping model in Azure Subscriptions Explained: Types, Billing Boundaries and When to Create a New One and Azure Resource Hierarchy Explained: Subscriptions, Resource Groups and Resources.
- Build the matching cost discipline with Azure Cost Management for Beginners: Budgets, Alerts and Cost Analysis in Your First 30 Days and right-size what you unlock via Azure Advisor for Cost: Acting on Rightsizing and Idle-Resource Recommendations.
- Pick VM sizes with both quotas and fixed limits in mind using Decoding Azure VM Series: Picking the Right D, E, F, L, N and M Family for Your Workload.
- Know the human path before you need it: Azure Support Plans Compared: Severity Levels, Response Times and What to Buy.
- Plan quota across regions for resilience with Azure Regions and Availability Zones: Designing for Resilience.