A brief service move should not become a failed checkout. Connection retry logic lets an application recover from a transient cloud database error within a bounded time. It must also know when retrying a write could create duplicate work.

Identify a Transient Failure
Cloud database services can move workloads, rebalance resources, or briefly interrupt a connection. The application sees an exception even when the database resumes quickly. A retry is appropriate for an error classified as transient, not for every failure. Bad credentials, invalid SQL, and a missing table need a fix, not repeated requests.
I start by logging error number, operation, attempt, and elapsed time. What failed: opening a connection, running a read, or committing a write? That distinction controls the retry. Treating all three as the same event is how a small outage becomes a duplicate order.
Keep Connection Retry Logic Within a Bounded Budget
A client needs a total deadline, a per-attempt timeout, and a maximum number of attempts. Exponential backoff increases the pause after each failure. Add a small random variation so many clients do not retry together. The total wait must fit the user experience. A background worker can usually tolerate a longer budget than an interactive request.
I set the budget before implementing the connection retry logic. Otherwise a command timeout followed by several long sleeps can hold a user for minutes. The error message should tell the user when work did not complete. Silence is not resiliency.
Separate Connection and Command Retries
A failed connection can be reopened after a transient condition clears. A failed command needs a fresh connection and a decision about transaction state. A read-only query is usually simpler to replay than a write. If a write committed but its acknowledgment was lost, repeating it can create a duplicate.
Design an idempotency key for business operations that can be retried. Store the key with the result in the same transaction. On a repeat request, return the recorded result rather than performing the action again. I check this path before enabling automatic retries on payment or order operations.
Inspect Driver Resiliency and Connection Retry Logic
Current SQL Server drivers expose connection resiliency features such as reconnecting a broken idle connection. That is useful, but it is not a promise to replay an in-flight transaction. Connection retry settings and command timeout need to fit together. Confirm the behavior for the exact driver version the application uses.
This SQL query shows the current session’s connection and encryption information. It cannot verify a driver’s retry policy, but it confirms which endpoint and transport the test reached. Pair it with a controlled connection interruption in a test environment.
SELECT c.session_id, c.connect_time,
c.net_transport, c.encrypt_option,
c.auth_scheme, c.client_net_address
FROM sys.dm_exec_connections AS c
WHERE c.session_id = @@SPID;
Build a Local Backoff Test
You can verify the delay schedule without connecting to a database. This PowerShell example calculates bounded exponential waits with jitter and prints each attempt. Replace the demonstration with a retry loop around the application’s supported driver calls. Keep error classification and total deadline in that loop.
The code does not hide an endless retry behind a friendly name. I want an operator to see exactly how long a request can remain pending.
# PowerShell
$maximumSeconds = 30
$elapsedSeconds = 0
foreach ($attempt in 1..5) {
$baseSeconds = [Math]::Min([Math]::Pow(2, $attempt), 8)
$delaySeconds = $baseSeconds + (Get-Random -Minimum 0 -Maximum 2)
if (($elapsedSeconds + $delaySeconds) -gt $maximumSeconds) { break }
"Attempt $attempt waits $delaySeconds seconds"
$elapsedSeconds += $delaySeconds
}Classify Errors Deliberately
Maintain a tested list of transient errors for the service and driver rather than guessing from message text. Error numbers and provider behavior can change. Log unclassified failures and let them surface clearly. A syntax error that is retried five times wastes time and hides the cause.
I review error frequency after deployment. A retry that succeeds can still signal an unhealthy service path if it occurs continually. Count retries, success after retry, exhausted budgets, and operation type. Resiliency should be visible in monitoring, not invisible to the people operating the application.
Handle the Uncertain Commit
The hardest case is a connection loss near COMMIT. The client does not know whether the database committed. A safe design checks an idempotency key or business identifier on reconnect. It does not blindly execute the write again. The answer must be correct even when two application instances retry at once.
A unique constraint can enforce the key. The example shows a minimal table definition for a test database. Define retention and ownership for keys in a real application. The database constraint is the final guard against duplicate processing.
CREATE TABLE dbo.RequestReceipt
(
RequestKey uniqueidentifier NOT NULL
CONSTRAINT PK_RequestReceipt PRIMARY KEY,
CompletedAtUtc datetime2(3) NOT NULL,
ResultCode int NOT NULL
);
SELECT RequestKey, CompletedAtUtc, ResultCode
FROM dbo.RequestReceipt
WHERE RequestKey = '00000000-0000-0000-0000-000000000001';Test Connection Retry Logic at Different Failure Moments
Simulate a failed initial connection, an idle connection broken before use, a query failure, and a lost connection during commit. The application’s behavior should be clear in each case. Verify that a nontransient error stops promptly. Verify that an exhausted retry budget produces a useful message and telemetry.
I also test many clients at once. Without jitter, synchronized retries can hammer a recovering database. A single local test does not show that wave. Use a controlled environment and watch connection count, latency, and failure rate while clients recover.
Keep the Database and App Aligned
The database can help with unique keys, short transactions, and clear error signals. The application owns its retry deadline and user message. Drivers can restore idle connections, but they cannot infer whether repeating a business transaction is safe. Document those boundaries for each important operation.
Connection retry logic is successful when a brief interruption stays brief for users and does not duplicate work. The trick is restraint. A retry loop should be easy to stop, easy to measure, and boring when the service is healthy.
Set a total deadline for the operation, not only a delay between tries. A client with many short retries can exceed the user’s request timeout even if each individual wait looks small. Log the attempt number, error code, delay, and final outcome without storing secrets. That gives support a sequence to inspect.
For writes, decide what the client does after losing the connection at commit time. A network error cannot tell you whether the transaction committed. Give the request an idempotency key, then query its receipt before sending the write again. I test this boundary deliberately. Repeating an INSERT blindly is not resilience. It is a duplicate generator with excellent persistence.
Related reading on this blog: Which SQL Server Client Driver to Use Now and SQL Azure Database: Msg 40197, Level 20: The Service has Encountered an Error Processing Your Request. Please Try Again. Error Code 40549.

A retry is not permission to repeat every command, it is a bounded recovery for classified failures.
Published by Pinal Dave on SQLAuthority. More of my work at pinaldave.com.




