Dynamics 365

Dynamics 365 Service Protection Limits: Why Your Integration Keeps Getting Throttled

If an integration into Dataverse keeps failing with 429 errors, it is not broken, it is being throttled on purpose. Here is what the service protection limits actually are and how to design around them properly.

Dynamics 365 Service Protection Limits Explained

Every Dynamics 365 project I have worked on eventually runs into the same conversation. An integration that worked fine in testing starts throwing 429 errors in production, someone assumes Dataverse is having a bad day, and a support ticket gets raised. Nine times out of ten there is nothing wrong with the platform at all. The integration has simply hit a service protection limit, and Microsoft is doing exactly what it is designed to do.

I have been the person debugging this more times than I can count, usually for a client who built an integration against a test environment with a handful of records and never once thought about what happens when it runs against a live database with real volume. It is one of the most common and most avoidable mistakes I see in Dynamics 365 implementations, so it is worth explaining properly rather than leaving it as folklore that gets passed around support desks.

What Service Protection Limits Actually Are

Dataverse, the data platform underneath Dynamics 365, applies per user limits to protect the shared infrastructure that every tenant sits on. There are three limits that matter in practice. You are allowed a maximum of 6,000 requests within a rolling five minute window per user. You are allowed a combined execution time of 20 minutes of processing within that same five minute window. And you are limited to 52 concurrent requests from a single user at any one time.

Breach any one of these and the platform returns a 429 response with a Retry After header telling you how long to wait. This is not a bug and it is not Microsoft being stingy. It is precisely the same principle I wrote about in my piece on building API rate limiting for small SaaS products, applied at genuinely enormous scale. One tenant's badly built integration should never be able to degrade performance for every other customer on the same infrastructure, and that is exactly what these limits exist to prevent.

Where Integrations Actually Fall Down

The Loop That Calls the API Once Per Record

This is the single most common cause I see. A developer writes an integration that loops through a batch of records from an external system and fires an individual create or update request to Dataverse for each one. It works perfectly with fifty test records. It falls over the moment someone runs a real overnight sync of ten thousand records, because that loop can burn through the request limit long before the batch finishes.

Synchronous Plugins Doing Too Much Work

The execution time limit catches people out just as often as the request count. A synchronous plugin that calls out to an external service, does heavy calculation, or triggers a chain of other plugins on save can eat into that twenty minute execution budget surprisingly fast under load, especially during a bulk data import when hundreds of records save in quick succession.

Polling Instead of Using Webhooks

I still see integrations built to poll Dataverse every few seconds asking whether anything has changed, rather than subscribing to webhooks or using the Dataverse change tracking API. This is the same lazy pattern I have criticised before when Dynamics 365 connectors poll rather than react, and it is one of the fastest ways to burn through your request allowance for no real benefit.

How to Design Around the Limits Properly

The fix is almost never to ask Microsoft for a higher limit, and honestly you should not want one. The fix is to design the integration properly in the first place.

Batch your requests wherever the API supports it. The Dataverse Web API supports batch operations that let you bundle multiple create, update or delete operations into a single HTTP request, which counts as one request against your limit rather than dozens. For genuinely large volumes, the bulk data load and Dataverse Import APIs exist specifically so you are not hammering the standard endpoints record by record.

Move heavy or non urgent work off the synchronous path entirely. Anything that does not need to complete before the user's save operation returns belongs in an asynchronous plugin, a Power Automate flow, or a queued Azure Function triggered from Service Bus. This is the same architectural instinct I apply on every Dynamics 365 integration project I work on, and it is the difference between an integration that scales gracefully and one that falls over the first time it meets real production volume.

Respect the Retry After header when you do get throttled. A properly built integration treats a 429 as a normal, expected response and backs off for the stated period before retrying, rather than hammering the endpoint again immediately, which only makes the situation worse and delays your own recovery.

Test at Realistic Volume Before You Go Live

The reason this catches so many teams out is that nobody tests an integration against production scale data before go live. Fifty records in a sandbox tells you almost nothing about how the integration behaves against fifty thousand. If a client is heading toward go live, load testing the integration against realistic volumes is one of the checks I insist on covering in my Dynamics 365 go live guide, because service protection throttling is exactly the kind of thing that only shows up under real load and is deeply unpleasant to discover for the first time on launch day.

My Honest Take

Service protection limits are not a nuisance to be engineered around with cleverness. They are Microsoft telling you, quite clearly, how the platform expects to be used at scale. Every time I have seen an integration hit them repeatedly, the actual problem was a design shortcut taken early in the project that nobody revisited once it started causing pain. Batch your calls, move heavy work off the synchronous path, use change tracking instead of polling, and you will very rarely think about these limits again. Fight them with retry loops and cleverness instead, and you will be fighting them forever.

If you are planning a Dynamics 365 integration and want someone who has actually hit these limits in production to sanity check the design before you build it, that is exactly the kind of conversation I have with clients through Dynamics 365 consulting. Getting the integration pattern right at design time is far cheaper than rebuilding it after a launch day incident.

More from the blog

Dynamics 3657 min read

Dynamics 365 Integration Patterns That Actually Hold Up

Read more
Technology7 min read

API Rate Limiting: A Practical Guide for Small SaaS Teams

Read more
Dynamics 3656 min read

The Dynamics 365 Go Live Guide: What I Check Before Launch

Read more