{"id":47798,"date":"2026-10-12T09:22:20","date_gmt":"2026-10-12T07:22:20","guid":{"rendered":"https:\/\/www.dbi-services.com\/blog\/?p=47798"},"modified":"2026-10-12T09:22:23","modified_gmt":"2026-10-12T07:22:23","slug":"calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance","status":"publish","type":"post","link":"https:\/\/www.dbi-services.com\/blog\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\/","title":{"rendered":"Calling AI from SQL Server 2025 can lock everyone out of your on-prem instance"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">With SQL Server 2025, Microsoft lets the database engine call an AI model by itself. <code><a href=\"https:\/\/learn.microsoft.com\/en-us\/sql\/relational-databases\/system-stored-procedures\/sp-invoke-external-rest-endpoint-transact-sql?view=sql-server-ver17&amp;tabs=request-headers\" data-type=\"link\" data-id=\"https:\/\/learn.microsoft.com\/en-us\/sql\/relational-databases\/system-stored-procedures\/sp-invoke-external-rest-endpoint-transact-sql?view=sql-server-ver17&amp;tabs=request-headers\">sp_invoke_external_rest_endpoint<\/a><\/code> sends an HTTPS request straight from T-SQL, to Azure OpenAI or to any other REST service, so an embedding or a completion no longer needs application code in between.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But what happens under heavy pressure, when hundreds of sessions make that call at the same moment and the model takes its time to answer? I ran this scenario on SQL Server 2025 and on Azure SQL Database, with the same procedure and the same load script. The two platforms do not react the same way at all.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>100 sessions calling a 30-second endpoint<\/th><th>SQL Server 2025<\/th><th>Azure SQL Database, 2 vCores<\/th><th>SQL Server 2025 with Resource Governor<\/th><\/tr><tr><td>Calls sent to the endpoint at once<\/td><td>100<\/td><td>22<\/td><td>22<\/td><\/tr><tr><td>What happens to the others<\/td><td>nothing holds them back<\/td><td>refused at once, error 10928<\/td><td>queued, all served after 150 s<\/td><\/tr><tr><td>Worker threads held<\/td><td>100<\/td><td>22<\/td><td>100<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The documentation of the procedure describes <a href=\"https:\/\/learn.microsoft.com\/en-us\/sql\/relational-databases\/system-stored-procedures\/sp-invoke-external-rest-endpoint-transact-sql?view=sql-server-ver17&amp;tabs=request-headers\" data-type=\"link\" data-id=\"https:\/\/learn.microsoft.com\/en-us\/sql\/relational-databases\/system-stored-procedures\/sp-invoke-external-rest-endpoint-transact-sql?view=sql-server-ver17&amp;tabs=request-headers\">a cap at 10% of the worker thread<\/a>s. That is not what I measured. Azure SQL Database does cap the calls in my tests, but at 15% of its workers: 22 calls at 2 vCores, 45 at 4 vCores, 30 on a Standard S3. SQL Server 2025 has no cap at all, and the rest of this post shows what happens without it.<\/p>\n\n\n\n<h2 id=\"h-the-lab\" class=\"wp-block-heading\">The lab<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The on-premises setup has three parts, all on one virtual machine (Windows Server 2022, 2 vCPUs): a load generator, a SQL Server 2025 Standard instance, and a small HTTPS endpoint that answers after the delay given in the URL.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"454\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-50-1024x454.png\" alt=\"\" class=\"wp-image-47808\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-50-1024x454.png 1024w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-50-300x133.png 300w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-50-767x340.png 767w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-50.png 1344w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The call is wrapped in a procedure, so that every session runs exactly the same thing:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; title: ; notranslate\" title=\"\">\nCREATE OR ALTER PROCEDURE dbo.CallSlowAi @delay int, @timeout smallint = 230\nAS\nBEGIN\n    DECLARE @url nvarchar(400) = CONCAT(N&#039;https:\/\/&lt;YOUR_VM&gt;:8443\/?delay=&#039;, @delay);\n    DECLARE @ret int, @resp nvarchar(max);\n    EXEC @ret = sp_invoke_external_rest_endpoint @url = @url, @method = &#039;POST&#039;,\n         @payload = N&#039;{&quot;input&quot;:&quot;hello&quot;}&#039;, @timeout = @timeout, @response = @resp OUTPUT;\n    RETURN @ret;\nEND\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The load generator is a PowerShell function that opens N connections without pooling, sends <code>EXEC dbo.CallSlowAi @delay = 30<\/code> on all of them at the same moment, and records for each session the elapsed time and the error number. One process, so the client itself does not slow the VM down.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Before measuring SQL Server, I called the endpoint directly with 200 parallel requests: they all came back in 30.6 seconds. The endpoint is not the bottleneck.<\/p>\n\n\n\n<h2 id=\"h-on-premises-no-limit-until-the-workers-run-out\" class=\"wp-block-heading\">On-premises: no limit, until the workers run out<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A worker thread is what SQL Server uses to execute a request: one request running, at least one worker busy. The instance has a fixed pool of them, set by <code>max worker threads<\/code>; with the default setting on this 2-vCPU machine, that is 512. When they are all taken, new work waits with the <code>THREADPOOL<\/code> wait type, and that includes logging in, because a login needs a worker too (see <a href=\"https:\/\/www.dbi-services.com\/blog\/when-an-idle-transaction-starves-the-worker-pool-threadpool\/\" data-type=\"link\" data-id=\"https:\/\/www.dbi-services.com\/blog\/when-an-idle-transaction-starves-the-worker-pool-threadpool\/\">my previous blog<\/a> about this wait type).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Three words matter here, and their numbers should not be added together. A <strong>session <\/strong>is a <strong>connection<\/strong>. When it runs a <strong>request<\/strong>, the request is split into one or more <strong>tasks<\/strong>, and each task needs a <strong>worker <\/strong>thread to run. A simple call like ours is one task, so one worker; a parallel query would take several. The worker counts I quote also include SQL Server&#8217;s own background tasks: about 45 workers on this idle instance. A wait type, on the other hand, is counted per task, whoever owns it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A session waiting for the endpoint reports the HTTP_EXTERNAL_CONNECTION wait type and keeps its worker thread for the whole wait: every waiting call added one worker to that baseline.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With 300 sessions, SQL Server sent everything at once. I counted 300 TCP connections from <code>sqlservr.exe<\/code> to port 8443, and all calls returned together:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: css; title: ; notranslate\" title=\"\">\nErrorNumber : 0\nSessions    : 300\nMinSec      : 30.2\nMaxSec      : 34.5\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">With 600 sessions, the instance has only 512 worker threads to give. 510 connections were open at the same time, and the calls finished in two groups:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: css; title: ; notranslate\" title=\"\">\nFinished after (s)   Sessions\n30                   193\n40                   316\n50                     1\n60                    90\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The first 509 calls left immediately, one per available worker. The last 91 did not wait for the endpoint: <strong>they waited for a worker<\/strong>. No error was raised at any point, and nothing held the calls back.<\/p>\n\n\n\n<h3 id=\"h-what-the-rest-of-the-instance-sees\" class=\"wp-block-heading\">What the rest of the instance sees<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">I measured the saturation itself during an earlier run of the same 600 sessions, with HTTP\/2 still enabled on the endpoint (see below). From the dedicated admin connection:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nactive_workers  queued_tasks\n556             154\n\n-------------------------------------\n\nwait_type                  n\nHTTP_EXTERNAL_CONNECTION   513\nTHREADPOOL                 154\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">At that moment an ordinary <code>sqlcmd<\/code> connection failed:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nSqlcmd: Error: Microsoft ODBC Driver 17 for SQL Server : Login timeout expired.\nSqlcmd: Error: Microsoft ODBC Driver 17 for SQL Server : Unable to complete login process due to delay in prelogin response.\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The admin connection kept answering, and the instance recovered by itself once the calls completed. <code>KILL<\/code> also works at once on a waiting session (error 596 on the client side).<\/p>\n\n\n\n<h3 id=\"h-http-2-changes-the-shape-not-the-outcome\" class=\"wp-block-heading\">HTTP\/2 changes the shape, not the outcome<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">HTTP.sys, which hosts my test endpoint, <a href=\"https:\/\/learn.microsoft.com\/en-us\/aspnet\/core\/fundamentals\/servers\/httpsys?view=aspnetcore-10.0\" data-type=\"link\" data-id=\"https:\/\/learn.microsoft.com\/en-us\/aspnet\/core\/fundamentals\/servers\/httpsys?view=aspnetcore-10.0\">offers HTTP\/2 by default<\/a>. In that mode SQL Server opened 6 TCP connections instead of one per call, and only 100 calls were in flight per host name. The same 300 sessions then finished in three waves:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nFinished after (s)   Sessions\n30                   100\n60                   100\n90                   100\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The queued sessions show the same <code>HTTP_EXTERNAL_CONNECTION<\/code> wait and hold a worker while they queue, so the pool empties just as well: the 556 workers above were measured in this mode. The queue has a second effect. <code>@timeout<\/code> keeps running while a call waits its turn. With a 30-second endpoint and <code>@timeout = 45<\/code>, the first 100 calls succeeded and the 100 queued ones failed after 45.5 seconds with error 31629, <em>The external rest endpoint execution exceeded the timeout value<\/em>, although the endpoint was answering normally.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Turning HTTP\/2 off on the endpoint removes that queue. I disabled it in HTTP.sys (<code>EnableHttp2Tls<\/code> and <code>EnableHttp2Cleartext<\/code> set to 0, then a reboot) and replayed the same load:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>300 sessions, 30-second endpoint<\/th><th>HTTP\/2<\/th><th>HTTP\/1.1<\/th><\/tr><\/thead><tbody><tr><td>TCP connections opened by SQL Server<\/td><td>6<\/td><td>300<\/td><\/tr><tr><td>Calls in flight at once<\/td><td>100<\/td><td>300<\/td><\/tr><tr><td>Last call returns after<\/td><td>90 s<\/td><td>34.5 s<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The waves are gone and so are the timeouts caused by the queue. It is not a fix for the instance, though. Each call still holds a worker, the 600-session run at the top of this section was made in HTTP\/1.1, and the endpoint now receives every call at once. With a real AI provider you also do not choose the protocol: the server does.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I did not capture the HTTP\/2 negotiation, so I cannot say which side sets the figure of 100. What the two modes show together is that SQL Server applies no cap of its own.<\/p>\n\n\n\n<h2 id=\"h-but-the-documentation-says-10\" class=\"wp-block-heading\">But the documentation says 10%?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The page of the procedure is marked as applying to SQL Server 2025, Azure SQL Database, Azure SQL Managed Instance and SQL database in Microsoft Fabric. Its <a href=\"https:\/\/learn.microsoft.com\/en-us\/sql\/relational-databases\/system-stored-procedures\/sp-invoke-external-rest-endpoint-transact-sql?view=sql-server-ver17&amp;tabs=request-headers#throttling\" data-type=\"link\" data-id=\"https:\/\/learn.microsoft.com\/en-us\/sql\/relational-databases\/system-stored-procedures\/sp-invoke-external-rest-endpoint-transact-sql?view=sql-server-ver17&amp;tabs=request-headers#throttling\">throttling section<\/a> reads:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><em>The number of concurrent connections to external endpoints done via <code>sp_invoke_external_rest_endpoint<\/code> are capped to 10% of worker threads, with a maximum of 150 workers.<\/em><\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">It adds that a call made beyond the limit raises error 10928. With 512 worker threads, I expected about 51 calls to pass and the others to fail. I got neither the cap nor the error, on RTM as on CU9.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The next sentence of that section gives a hint: it speaks of a <em>single database<\/em> and of an <em>elastic pool<\/em>, two notions that only exist in Azure SQL Database. So I ran the same test there.<\/p>\n\n\n\n<h2 id=\"h-azure-sql-database-22-calls-then-an-error\" class=\"wp-block-heading\">Azure SQL Database: 22 calls, then an error<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Azure SQL Database only calls endpoints from a <a href=\"https:\/\/learn.microsoft.com\/en-us\/sql\/relational-databases\/system-stored-procedures\/sp-invoke-external-rest-endpoint-transact-sql?view=sql-server-ver17&amp;tabs=request-headers#allowed-endpoints\" data-type=\"link\" data-id=\"https:\/\/learn.microsoft.com\/en-us\/sql\/relational-databases\/system-stored-procedures\/sp-invoke-external-rest-endpoint-transact-sql?view=sql-server-ver17&amp;tabs=request-headers#allowed-endpoints\">closed list<\/a> of Azure services, so the slow endpoint becomes an Azure Function. The database is a single Azure SQL Database in Switzerland North. I started on the vCore model, General Purpose serverless on standard-series (Gen5) hardware with 2 vCores maximum, then scaled the same database to 4 vCores, and finally to Standard S3 in the DTU model. The function runs on the Consumption plan, Node.js 22, in the same region. The procedure is the same, with the URL of the function, and the load script only changes its connection string.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"520\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-46-1024x520.png\" alt=\"\" class=\"wp-image-47800\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-46-1024x520.png 1024w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-46-300x152.png 300w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-46-767x389.png 767w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-46.png 1344w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Before any load, the governance view of the database already shows a dedicated limit:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; title: ; notranslate\" title=\"\">\nSELECT primary_group_max_workers, primary_group_max_outbound_connection_workers\nFROM sys.dm_user_db_resource_governance;\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nprimary_group_max_workers  primary_group_max_outbound_connection_workers\n150                        22\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">I stated my bet before running the load: 22 successes, 78 errors. Result for 100 sessions calling a 30-second endpoint:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: css; title: ; notranslate\" title=\"\">\nErrorNumber  Sessions  Finished after (s)\n0            22        30\n10928        78        0\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nResource ID : 4. The outbound connection worker limit for the database is 22 and has been reached.\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The 78 rejected sessions got their answer immediately, which leaves the database 128 of its 150 workers for everything else, whatever the endpoint does.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Two remarks on this test. The ratio is 15%, not <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/azure-sql\/database\/resource-limits-logical-server?view=azuresql#external-connections\" data-type=\"link\" data-id=\"https:\/\/learn.microsoft.com\/en-us\/azure\/azure-sql\/database\/resource-limits-logical-server?view=azuresql#external-connections\">the documented 10%<\/a>. At 2 vCores the database has 150 workers and a limit of 22. I scaled it to 4 vCores: 300 workers, a limit of 45, and the same load gave 45 successes and 55 errors. In the <strong>DTU model<\/strong>, a Standard S3 shows 200 workers and a limit of 30. This is one database, in one region, read on three service objectives and load-tested on two. The ratio could differ on other tiers, hardware generations or Hyperscale, and Microsoft may change it: treat 15% as what I observed, not as a rule. On the endpoint side I needed to do a small adjustment as well: an Azure Function on the Consumption plan served only 100 concurrent requests per instance until I raised <code>maxConcurrentRequests<\/code> in <code>host.json<\/code>. A direct test of 200 parallel requests took 62.8 seconds before the change and 30.4 after.<\/p>\n\n\n\n<h2 id=\"h-the-same-limit-on-premises-with-resource-governor\" class=\"wp-block-heading\">The same limit on-premises, with Resource Governor<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">SQL Server 2025 exposes nothing comparable. On CU9, <code>sys.dm_user_db_resource_governance<\/code> does not exist, no system column deals with outbound connections, and the only related configuration option is the on\/off switch <code>external rest endpoint enabled<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">What SQL Server does have is Resource Governor, and a workload group can limit its number of concurrent requests. I created a group with the Azure value and sent the sessions of the load generator into it through their application name:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; title: ; notranslate\" title=\"\">\nUSE master;\nGO\nCREATE WORKLOAD GROUP AiCalls WITH (GROUP_MAX_REQUESTS = 22) USING &#x5B;default];\nGO\nCREATE FUNCTION dbo.RgClassifier() RETURNS sysname WITH SCHEMABINDING\nAS\nBEGIN\n    RETURN CASE WHEN APP_NAME() = N&#039;AiLoad&#039; THEN N&#039;AiCalls&#039; ELSE N&#039;default&#039; END;\nEND\nGO\nALTER RESOURCE GOVERNOR WITH (CLASSIFIER_FUNCTION = dbo.RgClassifier);\nALTER RESOURCE GOVERNOR RECONFIGURE;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Same load as on Azure, 100 sessions calling a 30-second endpoint:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: css; title: ; notranslate\" title=\"\">\nErrorNumber  Sessions\n0            100\n\nFinished after (s)   Sessions\n30                   22\n60                   22\n90                   22\n120                  22\n150                  12\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The limit is applied to the unit: never more than 22 calls reach the endpoint. But there is no error. Every session ends up being served, and the last ones wait two minutes for it.<\/p>\n\n\n\n<h2 id=\"h-where-resource-governor-stops\" class=\"wp-block-heading\">Where Resource Governor stops<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">During the second wave of that test, the group, the waits and the workers looked like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"660\" height=\"817\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-48.png\" alt=\"\" class=\"wp-image-47802\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-48.png 660w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-48-242x300.png 242w\" sizes=\"auto, (max-width: 660px) 100vw, 660px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The 56 queued sessions wait on <code>RESMGR_THROTTLED<\/code>, and each of them has a worker. The instance counts 123 active workers against 45 at rest: 78 more, exactly the 22 calls in flight plus the 56 sessions in the queue.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"443\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-47-1024x443.png\" alt=\"\" class=\"wp-image-47801\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-47-1024x443.png 1024w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-47-767x332.png 767w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-47-300x130.png 300w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-47.png 1344w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Beyond the 22nd call<\/th><th>Azure SQL Database<\/th><th>SQL Server 2025 with Resource Governor<\/th><\/tr><tr><td>What the session gets<\/td><td>error 10928, immediately<\/td><td>a place in a queue<\/td><\/tr><tr><td>Worker of that session<\/td><td>released<\/td><td>held until its turn comes and the call returns<\/td><\/tr><tr><td>Calls reaching the endpoint<\/td><td>22<\/td><td>22<\/td><\/tr><tr><td>Worker pool<\/td><td>protected<\/td><td>not protected<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Resource Governor protects the service being called. It does not protect the instance. With 600 sessions classified in that group, 22 calls would be in flight and the 578 others would still be queued, each holding a worker, against a pool of 512. I did not run that last case; it follows from the two measurements above.<\/p>\n\n\n\n<h2 id=\"h-what-to-take-from-this\" class=\"wp-block-heading\">What to take from this<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">On SQL Server 2025, every session waiting for an external endpoint holds a worker thread, and the engine sets no limit on how many can wait at once. Azure SQL Database does have such a cap, at 15% of its workers in my tests rather than the documented 10%, and a call beyond it is refused immediately. On-premises, a slow AI service plus a concurrent application is enough to exhaust the worker pool and to keep new connections out, with no blocking chain to look for and an error message, when there is one, that points at the endpoint.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The difference is also one of scope. In Azure SQL Database, the limit belongs to the <strong>database<\/strong>: a flood of slow calls is refused at the door of that database, and the 128 workers left keep it running. In SQL Server, the worker pool belongs to the instance. Every database on it <strong>shares the same 512 workers<\/strong>, so one application calling a slow AI service can lock out the users of all the others.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Resource Governor can cap the number of calls sent to the service, in Standard Edition too, but it queues the surplus instead of refusing it, and a queued session costs a worker. If you want the Azure behavior, the refusal has to come from the code that makes the call, or from the application in front of it. Make sure you can reach the dedicated admin connection before you need it: it works locally out of the box (<code>sqlcmd -A<\/code>), but from another machine it requires the <code>remote admin connections<\/code> option. It was the only way in during the saturation, and <code>KILL<\/code> on the waiting sessions frees their workers at once.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>sp_invoke_external_rest_endpoint has no limit in SQL Server 2025: each waiting call holds a worker. Compared with Azure SQL.<\/p>\n","protected":false},"author":157,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":"","_members_access_role":[],"_members_access_error":""},"categories":[368,99],"tags":[3490,51],"type_dbi":[],"class_list":["post-47798","post","type-post","status-publish","format-standard","hentry","category-development-performance","category-sql-server","tag-aidevelopment","tag-sql-server"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v28.6 (Yoast SEO v28.6) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Calling AI from SQL Server 2025 can lock everyone out of your on-prem instance - dbi Blog<\/title>\n<meta name=\"description\" content=\"sp_invoke_external_rest_endpoint has no limit in SQL Server 2025: each waiting call holds a worker. Compared with Azure SQL.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.dbi-services.com\/blog\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Calling AI from SQL Server 2025 can lock everyone out of your on-prem instance\" \/>\n<meta property=\"og:description\" content=\"sp_invoke_external_rest_endpoint has no limit in SQL Server 2025: each waiting call holds a worker. Compared with Azure SQL.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.dbi-services.com\/blog\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\/\" \/>\n<meta property=\"og:site_name\" content=\"dbi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-12T07:22:20+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-12T07:22:23+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-50.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1344\" \/>\n\t<meta property=\"og:image:height\" content=\"596\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Louis Tochon\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Louis Tochon\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\\\/\"},\"author\":{\"name\":\"Louis Tochon\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/e4195b0cb120295b3407a502c23e75b6\"},\"headline\":\"Calling AI from SQL Server 2025 can lock everyone out of your on-prem instance\",\"datePublished\":\"2026-10-12T07:22:20+00:00\",\"dateModified\":\"2026-10-12T07:22:23+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\\\/\"},\"wordCount\":1930,\"commentCount\":0,\"image\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2026\\\/10\\\/image-50-1024x454.png\",\"keywords\":[\"AIDevelopment\",\"SQL Server\"],\"articleSection\":[\"Development &amp; Performance\",\"SQL Server\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\\\/\",\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\\\/\",\"name\":\"Calling AI from SQL Server 2025 can lock everyone out of your on-prem instance - dbi Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2026\\\/10\\\/image-50-1024x454.png\",\"datePublished\":\"2026-10-12T07:22:20+00:00\",\"dateModified\":\"2026-10-12T07:22:23+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/e4195b0cb120295b3407a502c23e75b6\"},\"description\":\"sp_invoke_external_rest_endpoint has no limit in SQL Server 2025: each waiting call holds a worker. Compared with Azure SQL.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2026\\\/10\\\/image-50.png\",\"contentUrl\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2026\\\/10\\\/image-50.png\",\"width\":1344,\"height\":596},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Calling AI from SQL Server 2025 can lock everyone out of your on-prem instance\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/\",\"name\":\"dbi Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/e4195b0cb120295b3407a502c23e75b6\",\"name\":\"Louis Tochon\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ce0ee48c64e763e6c4076e21c80729d15bc4493288aeb8695125c69082100e10?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ce0ee48c64e763e6c4076e21c80729d15bc4493288aeb8695125c69082100e10?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ce0ee48c64e763e6c4076e21c80729d15bc4493288aeb8695125c69082100e10?s=96&d=mm&r=g\",\"caption\":\"Louis Tochon\"},\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/author\\\/louistochon\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Calling AI from SQL Server 2025 can lock everyone out of your on-prem instance - dbi Blog","description":"sp_invoke_external_rest_endpoint has no limit in SQL Server 2025: each waiting call holds a worker. Compared with Azure SQL.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.dbi-services.com\/blog\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\/","og_locale":"en_US","og_type":"article","og_title":"Calling AI from SQL Server 2025 can lock everyone out of your on-prem instance","og_description":"sp_invoke_external_rest_endpoint has no limit in SQL Server 2025: each waiting call holds a worker. Compared with Azure SQL.","og_url":"https:\/\/www.dbi-services.com\/blog\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\/","og_site_name":"dbi Blog","article_published_time":"2026-10-12T07:22:20+00:00","article_modified_time":"2026-10-12T07:22:23+00:00","og_image":[{"width":1344,"height":596,"url":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-50.png","type":"image\/png"}],"author":"Louis Tochon","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Louis Tochon","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.dbi-services.com\/blog\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\/#article","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\/"},"author":{"name":"Louis Tochon","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/e4195b0cb120295b3407a502c23e75b6"},"headline":"Calling AI from SQL Server 2025 can lock everyone out of your on-prem instance","datePublished":"2026-10-12T07:22:20+00:00","dateModified":"2026-10-12T07:22:23+00:00","mainEntityOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\/"},"wordCount":1930,"commentCount":0,"image":{"@id":"https:\/\/www.dbi-services.com\/blog\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\/#primaryimage"},"thumbnailUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-50-1024x454.png","keywords":["AIDevelopment","SQL Server"],"articleSection":["Development &amp; Performance","SQL Server"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.dbi-services.com\/blog\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.dbi-services.com\/blog\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\/","url":"https:\/\/www.dbi-services.com\/blog\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\/","name":"Calling AI from SQL Server 2025 can lock everyone out of your on-prem instance - dbi Blog","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\/#primaryimage"},"image":{"@id":"https:\/\/www.dbi-services.com\/blog\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\/#primaryimage"},"thumbnailUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-50-1024x454.png","datePublished":"2026-10-12T07:22:20+00:00","dateModified":"2026-10-12T07:22:23+00:00","author":{"@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/e4195b0cb120295b3407a502c23e75b6"},"description":"sp_invoke_external_rest_endpoint has no limit in SQL Server 2025: each waiting call holds a worker. Compared with Azure SQL.","breadcrumb":{"@id":"https:\/\/www.dbi-services.com\/blog\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.dbi-services.com\/blog\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.dbi-services.com\/blog\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\/#primaryimage","url":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-50.png","contentUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2026\/10\/image-50.png","width":1344,"height":596},{"@type":"BreadcrumbList","@id":"https:\/\/www.dbi-services.com\/blog\/calling-ai-from-sql-server-2025-can-lock-everyone-out-of-your-on-prem-instance\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/www.dbi-services.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Calling AI from SQL Server 2025 can lock everyone out of your on-prem instance"}]},{"@type":"WebSite","@id":"https:\/\/www.dbi-services.com\/blog\/#website","url":"https:\/\/www.dbi-services.com\/blog\/","name":"dbi Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/e4195b0cb120295b3407a502c23e75b6","name":"Louis Tochon","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/ce0ee48c64e763e6c4076e21c80729d15bc4493288aeb8695125c69082100e10?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/ce0ee48c64e763e6c4076e21c80729d15bc4493288aeb8695125c69082100e10?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/ce0ee48c64e763e6c4076e21c80729d15bc4493288aeb8695125c69082100e10?s=96&d=mm&r=g","caption":"Louis Tochon"},"url":"https:\/\/www.dbi-services.com\/blog\/author\/louistochon\/"}]}},"_links":{"self":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/47798","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/users\/157"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/comments?post=47798"}],"version-history":[{"count":33,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/47798\/revisions"}],"predecessor-version":[{"id":47838,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/47798\/revisions\/47838"}],"wp:attachment":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/media?parent=47798"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/categories?post=47798"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/tags?post=47798"},{"taxonomy":"type","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/type_dbi?post=47798"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}