Resource Manager throttling and long-running operations

How Azure Resource Manager limits and completes requests — the 2024 regional token-bucket limits (per subscription, per service principal, per operation type), the x-ms-ratelimit-remaining headers, 429 with Retry-After and provider-specific throttles, how the TypeScript SDK retries by default (3 retries, Retry-After honoured) and how to tune it, and how asynchronous operations report progress (201/202, Azure-AsyncOperation, Location, provisioningState) and are awaited with SDK pollers.

markdownreferencev11VD0-ZV4Astage: buildtrust: officialservice: arminterface: sdkinterface: cliinterface: restARM throttling429 Too Many RequestsRetry-Aftertoken bucket Azure Resource Managerx-ms-ratelimit-remaining-subscription-readsx-ms-ratelimit-remaining-subscription-writesSubscriptionRequestsThrottledprovider throttling Microsoft.Networkmetrics API throttling getBatchretryOptions maxRetrieslong-running operationAzure-AsyncOperation headerLocation header 202provisioningState Succeeded Failed CanceledPollerLikebeginCreateOrUpdateAndWait deprecatedaz resource wait--no-wait

Created 21 Oct 2026 · Modified 23 Oct 2026 · 1 version

Throttling limits

Since 2024, Resource Manager throttles per region with a token bucket. A burst can spend the whole bucket; it then refills at a steady rate.

ScopeOperationBucketRefill per second
Subscriptionreads25025
Subscriptionwrites20010
Subscriptiondeletes20010
Tenantreads / writes / deletes250 / 200 / 20025 / 10 / 10
  • Subscription limits apply per service principal and per operation type. A global subscription limit is 15 times that, across all principals. One noisy identity throttles itself first.
  • Free and trial subscriptions may get less.
  • Providers throttle separately, per region of the resource: for example Microsoft.Network allows 1,000 writes and 10,000 reads per 5 minutes; Compute, Storage, Key Vault and Resource Graph have their own limits. Some providers return 429 for a temporary resource state, not volume.
  • Metrics reads (…/providers/microsoft.insights/metrics) are a common cause of subscription throttling. Use the batch metrics API.

What you get: HTTP 429 with a Retry-After value in seconds. Requests sent before it elapses count against you. Remaining budget appears in response headers: x-ms-ratelimit-remaining-subscription-reads, -writes, -deletes, and the tenant variants. Background-job throttling looks different: The request for subscription '…' could not be processed due to an excessive volume of traffic. Please try again later.

Retries in the TypeScript SDK

Every @azure/* client runs defaultRetryPolicy (@azure/core-rest-pipeline 1.25): it retries on 429 using Retry-After, on transport errors (DNS, resets), and otherwise with exponential backoff. Defaults: 3 retries, starting at 1 second. For batch scripts, raise it rather than writing your own loop:

import { DefaultAzureCredential } from "@azure/identity";
import { ResourceManagementClient } from "@azure/arm-resources";

const client = new ResourceManagementClient(new DefaultAzureCredential(), process.env.AZURE_SUBSCRIPTION_ID ?? "", {
  retryOptions: { maxRetries: 8, retryDelayInMs: 2000, maxRetryDelayInMs: 60000 },
});

// Reads in a loop are the usual throttle source: list once, not get per item.
for await (const rg of client.resourceGroups.list()) {
  console.log(rg.name, rg.location);
}

From the CLI, az retries too; for scripts, prefer one az resource list or Resource Graph query over hundreds of show calls.

Long-running operations

A create, update or delete that can't finish at once returns 201 Created or 202 Accepted and a provisioningState that isn't terminal (Succeeded, Failed and Canceled are terminal). To follow it:

  1. If the response has Azure-AsyncOperation, poll that URL. Its body carries the status.
  2. Otherwise poll the Location URL until it stops returning 202.
  3. Wait Retry-After seconds between polls when it's given. Accept status URLs of at least 4 KB.

In the TypeScript SDK the poller does this. In the 2026 packages (@azure/arm-resourcesdeployments, @azure/arm-resources 8), long-running methods return a PollerLike you can simply await; the older begin…AndWait helpers still exist but are marked deprecated:

import { DefaultAzureCredential } from "@azure/identity";
import { DeploymentsClient } from "@azure/arm-resourcesdeployments";

const deployments = new DeploymentsClient(new DefaultAzureCredential(), process.env.AZURE_SUBSCRIPTION_ID ?? "");

export async function deploy(resourceGroup: string, name: string, template: object) {
  const result = await deployments.deployments.createOrUpdate(resourceGroup, name, {
    properties: { mode: "Incremental", template },
  });
  return result.properties?.provisioningState; // terminal state
}

CLI: commands wait by default; --no-wait returns at once, and az resource wait --ids <id> --created (or --updated, --deleted, --custom "<JMESPath>") waits later.

A terminal Failed carries the operation's error. For deployments, read the failed operations (guides/arm/debug-failed-deployment.md).

Read this document as markdown — the same bytes an agent receives.