SharePoint Online Throttling (429 and 503): Why It Happens, How Retry-After Works, and Scripts That Don't Get Blocked

SharePoint Online returns 429 Too Many Requests (or 503 Server Too Busy) when one user or app sends more requests than it allows in a time window, and includes a Retry-After header saying how many seconds to wait. Wait that long and retry; retrying sooner extends the block. Then send fewer requests: select only the fields you need, page large lists, batch updates, run outside business hours, use app-only with a certificate, and decorate traffic with a User-Agent.

Published:

Last updated: 2026-10-29

What throttling looks like

During a toolkit inventory of 765 sites and 3,369 lists, SharePoint throttled us several times. The log shows what SharePoint said each time:

Logs filtered to thrott: HTTP (429) Throttling detected, waiting up to 45 seconds and 68 seconds; SharePoint asked us to wait 45 seconds before retrying; lowering the request rate to 2 requests per second; Throttling ended
SharePoint asked for 68 seconds, later 45. The rate dropped to 10, then 2 requests a second, and threads resumed when throttling ended.
  • 429 Too Many Requests: you, as a user or an app, sent too much in a short window.
  • 503 Server Too Busy: the service is under load; it's also throttling and also carries Retry-After.
  • Retry-After: seconds to wait. Our waits were 45 and 68 seconds; they can be longer.
  • Retrying before Retry-After has passed counts against you and makes the block longer. Repeated heavy throttling can end in the app or user being blocked for longer periods.

Limits aren't published as fixed numbers. They're per user and per app, per tenant, and depend on time of day and the cost of each request. A query that scans a large list costs more than one that reads an item by ID.

Option 1: Reduce load without code changes

  • Run big jobs outside business hours in the tenant's region. Limits are tighter when users are active.
  • Split the work. One script per site collection, run one after another, rather than many in parallel under the same account.
  • Don't run several heavy tools at once with the same account or app; they share its limit.
  • Check the SharePoint admin center, Reports, and Microsoft 365 service health, if throttling starts suddenly. 503s during an incident aren't your script.

Option 2: Make PowerShell scripts throttle-safe

Honor Retry-After

PnP PowerShell already retries CSOM requests (most Get-PnP* and Set-PnP* cmdlets) with backoff. Your own REST and Graph calls don't. This wrapper retries 429 and 503, waits exactly as long as Retry-After says, and gives up after a few tries:

function Invoke-SPWithRetry {
    param([scriptblock]$Request, [int]$MaxRetries = 6)
    for ($try = 1; ; $try++) {
        try { return & $Request }
        catch {
            $resp = $_.Exception.Response
            $code = if ($resp) { [int]$resp.StatusCode } else { 0 }
            if ($code -notin 429, 503 -or $try -gt $MaxRetries) { throw }
            $wait = 0
            $ra = $resp.Headers | Where-Object { $_.Key -eq "Retry-After" } | Select-Object -First 1
            if ($ra) { $wait = [int]($ra.Value | Select-Object -First 1) }
            if ($wait -le 0) { $wait = [math]::Min(300, [math]::Pow(2, $try) * 5) }   # no header: back off
            Write-Warning ("HTTP {0}; waiting {1}s (attempt {2} of {3})" -f $code, $wait, $try, $MaxRetries)
            Start-Sleep -Seconds $wait
        }
    }
}

# Example: a REST call with a decorated User-Agent
$headers = @{ Authorization = "Bearer $token"; Accept = "application/json;odata=nometadata"
              "User-Agent" = "NONISV|Contoso|SiteReport/1.0" }
$web = Invoke-SPWithRetry { Invoke-RestMethod -Uri "$SiteUrl/_api/web?`$select=Title" -Headers $headers }

This uses PowerShell 7's HttpResponseMessage headers. For a PnP connection, get the token with Get-PnPAccessToken -ResourceTypeName SharePoint, or call Invoke-PnPSPRestMethod inside the wrapper.

Send fewer, cheaper requests

Instead ofDo
Get-PnPListItem -List $l (every field)-Fields Title, Modified -PageSize 2000
One update per itemNew-PnPBatch / Invoke-PnPBatch, 100 operations per request
Reading everything again each runOnly items modified since the last run (CAML on Modified, or Graph delta)
Loops of Get-PnPProperty per itemLoad the property in the first query with -Includes where the cmdlet supports it
Many parallel threads2 to 4 at most per account, slowed down when a 429 arrives
Delegated sign-in for big jobsApp-only with a certificate, which has its own limits apart from the user's (how to set it up)

Microsoft asks that apps decorate traffic with a User-Agent in the form NONISV|CompanyName|AppName/Version (or ISV|... for vendors). Decorated traffic is prioritized over undecorated traffic when throttling decisions are made.

For storage cleanups, prefer server-side jobs such as New-SPOSiteFileVersionBatchDeleteJob over per-file loops; see bulk deleting old versions.

Option 3: Let SharePoint Essentials Toolkit handle it

The toolkit applies all of this to its own requests. When SharePoint returns 429 or 503, it reads Retry-After, holds every thread for that long, and lowers its request rate until throttling stops. The status bar says what's happening while you wait:

Site inventory running at 92 percent, 706 of 765 sites, with the status bar showing HTTP (429) Throttling detected, waiting up to 45 seconds for throttling to end
The job keeps running; it pauses requests, not progress already made.

Our 765-site inventory finished in 18 minutes with throttling included, and nothing had to be re-run. Every throttling event is in the job's Logs, so you can see when SharePoint pushed back and plan large jobs for quieter hours, or schedule them.

Community Edition is free on up to 20 sites per Microsoft 365 tenant.

Frequently asked questions

What does 429 Too Many Requests mean in SharePoint Online?

SharePoint is throttling you: your user or app sent more requests than it allows in a time window. The response has a Retry-After header with the number of seconds to wait before retrying.

How long does SharePoint throttling last?

As long as Retry-After says, often seconds to a couple of minutes; we saw 45 and 68 seconds. Retrying early makes it longer, and sustained heavy traffic can lead to longer blocks.

Does PnP PowerShell handle SharePoint throttling?

For CSOM-based cmdlets, yes; it retries with backoff. Your own Invoke-RestMethod or Graph calls need a retry wrapper that reads Retry-After.

Is 503 Server Too Busy also throttling?

Usually, yes. SharePoint returns 503 with Retry-After when the service is under load. Treat it like a 429. During a service incident, check Microsoft 365 service health.

How do I avoid SharePoint throttling in large scripts?

Select only needed fields, page large lists, batch updates, limit parallel threads, run outside business hours, use app-only with a certificate, and set a User-Agent like NONISV|Company|App/1.0.

Run large SharePoint reports without fighting throttling, free

SharePoint Essentials Toolkit Community Edition is free. Inventory, permissions and storage reports wait out throttling for you and log every event, on up to 20 sites per Microsoft 365 tenant. Get your free Community Edition license key.

About the author. The Cognillo SharePoint Team builds and supports SharePoint Essentials Toolkit and has worked with SharePoint administrators on permissions audits, migrations and cleanup projects since 2012.