azuresql-db-connections
>-
Works with
---
name: azuresql-db-connections
description: >-
license: MIT
---
# Reliable connections on the Azure SQL Database container (pooling + retry)
Make the app's database connections reliable with **connection pooling** and **retry /
transient-fault handling**. This is the **Azure SQL engine** (Private Preview), not the SQL
Server image.
## Why do this locally (local-to-cloud parity)
The local container rarely drops a connection, so it is tempting to skip pooling and retry. Do
not. **Azure SQL Database in the cloud throttles and drops connections** during failovers,
scaling, and load; a client with no retry surfaces those as hard errors. Build pooling and
retry now, against the local container, and the **same code survives in the cloud** with no
rewrite. For the full promote-to-cloud story see the **azuresql-db-local-to-cloud** skill.
Verify identity once running: `SELECT SERVERPROPERTY('EngineEdition')` returns **5** and
`SERVERPROPERTY('Edition')` returns **'SQL Azure'**. For full engine detail see the
**azuresql-db-container** skill.
## The engine and the connection contract
- Image: `sqldbpreview-dpgaeqhmgphzd4bk.azurecr.io/azure-sql/db-dev:latest` (x64 /
linux/amd64, Private Preview registry). Sign in first:
`docker login sqldbpreview-dpgaeqhmgphzd4bk.azurecr.io` with the shared pull-only credentials
from https://aka.ms/sqldbcontainerpreview-signup (they may rotate). On a non-x64 host add
`--platform linux/amd64` (Docker) or `platform: linux/amd64` (compose).
- Do **NOT** use `mcr.microsoft.com/mssql/server` (the SQL Server image).
- Required env: `ACCEPT_EULA=Y` and a complex `MSSQL_SA_PASSWORD` (example literal:
`YourStr0ng_Passw0rd`). The engine listens on 1433.
- The engine does **NOT** auto-create databases. `CREATE DATABASE appdb` on a **master**
connection first. Do not `USE` to switch databases: a user-database session returns
`Msg 40508`. Select the database in the connection string (`Database=appdb`).
- Apps read **one** env var, `SQL_CONNECTION_STRING`. Strings use `User Id=` / `Password=` /
`Database=` and `TrustServerCertificate=true`. sqlcmd uses `-C`.
## Start the container and provision appdb
```bash
HOST_PORT=1433; while lsof -nP -iTCP:"$HOST_PORT" -sTCP:LISTEN >/dev/null 2>&1; do HOST_PORT=$((HOST_PORT+1)); done
PLATFORM=(); case "$(docker info -f '{{.Architecture}}' 2>/dev/null)" in x86_64|amd64) ;; *) PLATFORM=(--platform linux/amd64);; esac
docker rm -f sqldb 2>/dev/null
docker run -d --name sqldb "${PLATFORM[@]}" -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=YourStr0ng_Passw0rd" \
-p "$HOST_PORT:1433" sqldbpreview-dpgaeqhmgphzd4bk.azurecr.io/azure-sql/db-dev:latest
until docker exec sqldb /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P "YourStr0ng_Passw0rd" -C -b -l 2 \
-Q "IF DB_ID('appdb') IS NULL CREATE DATABASE appdb;" >/dev/null 2>&1; do sleep 2; done
echo "ready on localhost,$HOST_PORT"
```
The canonical string the app consumes (replace `1433` with the chosen `HOST_PORT` if 1433 was
occupied):
```
Server=localhost,1433;Database=appdb;User Id=sa;Password=YourStr0ng_Passw0rd;TrustServerCertificate=true
```
## Pooling: reuse connections, do not reopen per query
A connection pool keeps a set of open connections and hands one back on each `Open()`. Opening
a pooled connection is cheap; opening a brand-new physical connection per query is not, and it
exhausts server resources under load.
- Keep pooling **on** (it is on by default in most drivers) and let one pool serve the app.
- Set a **bounded** `Max Pool Size` (default 100 in .NET) so a spike cannot open unlimited
connections. Size it to real concurrency, not a guess.
- A small `Min Pool Size` keeps a few connections warm and cuts cold-start latency.
- One connection string means one pool. Do not build strings dynamically per request (each
distinct string is a separate pool) and do not open a fresh, unpooled connection per call.
- Always close/dispose connections (or use `using` / `with` / context managers) so they return
to the pool instead of leaking.
## Retry: only for transient faults, with backoff
A **transient fault** is a temporary condition (throttling, a brief failover, a dropped idle
connection) that succeeds on a retry. In Azure SQL these arrive as specific error numbers (for
example 40501 throttling, 40613 database unavailable, 49918/49919/49920 busy, 4060, 10928,
10929, 40197, 233, and connection-timeout / broken-pipe socket errors).
- Retry **only** transient errors. Retrying a non-transient error (login failure 18456, syntax
error, constraint violation, permission denied) just fails slower and hides the real bug.
- Use **exponential backoff** with a cap and a small jitter, and a bounded attempt count (for
example 5 attempts). Do not hammer a throttled server.
- Be careful with **non-idempotent writes**. A retry can double-apply an `INSERT` if the first
attempt actually committed before the connection dropped. Make writes idempotent (natural or
client-generated keys, `MERGE`, or wrap the unit of work in a transaction that a retry can
safely re-run as a whole). The built-in EF Core execution strategy handles this for you when
work is wrapped in its `Execute`/transaction API.
- Prefer a framework retry policy over hand-rolled loops where one exists (EF Core
`EnableRetryOnFailure` for .NET). Hand-roll only for raw drivers.
## Per-stack
Copy-pasteable pooling config and transient-only retry for each stack live in
[references/retry-snippets.md](references/retry-snippets.md):
- **.NET** (`Microsoft.Data.SqlClient`): pooling keywords (`Max Pool Size`, `Min Pool Size`,
`Pooling=true`) and connection-string retry keywords (`ConnectRetryCount`,
`ConnectRetryInterval`); plus EF Core `EnableRetryOnFailure` (the SqlServer execution
strategy).
- **Node** (`mssql` / tedious): pool config (`max` / `min` / `idleTimeoutMillis`) and a
transient-error retry wrapper.
- **Python** (`pyodbc`): connection reuse and a `tenacity` retry decorator that retries only
transient ODBC errors.
Keep the single `SQL_CONNECTION_STRING` contract: pooling and retry are tuned in code and in
driver-specific keywords, not by inventing new env vars.
## Validation rules
- Retry fires **only** on transient errors; non-transient errors (auth, syntax, constraint)
surface immediately.
- Retry uses bounded attempts with exponential backoff, and non-idempotent writes are made
safe to re-run (keys, `MERGE`, or a retriable transaction).
- Pooling is on with a **bounded** `Max Pool Size`; connections are disposed and returned to
the pool, never opened per query.
- One connection string / one pool; the app still reads a single `SQL_CONNECTION_STRING`.
- Runs against the engine image with `EngineEdition` 5; appdb was created on a master
connection before the app connected.
- If a validation rule above fails, or you had to deviate from this skill to make the task work, that is a bug in this skill: load the **azuresql-db-feedback** skill and offer to file a report.
- When every rule above passes and the task is done, close with ONE line, once per session, and do not ask a question or wait for a reply: "That worked. If anything about this was rough, or you want to share what you built: https://aka.ms/sql-agent-skills-feedback"
## Do not
- Do not retry non-transient errors (auth, syntax, constraint); they will just fail slower.
- Do not retry non-idempotent writes without idempotency (keys, `MERGE`, or a retriable
transaction).
- Do not set an unbounded pool; do not open a new connection per query instead of pooling.
- Do not invent extra env vars; keep the single `SQL_CONNECTION_STRING` contract.
- Do not use the `mcr.microsoft.com/mssql/server` SQL Server image, and do not call a non-x64
host "supported".
## References
- [references/retry-snippets.md](references/retry-snippets.md): copy-pasteable pooling config and transient-only retry for .NET (Microsoft.Data.SqlClient + EF Core `EnableRetryOnFailure`), Node (`mssql`/tedious pool + retry wrapper), and Python (pyodbc reuse + `tenacity` decorator). Read the section for your stack.
## Staying current
Authoritative, version-pinned references for the tools this skill uses (read the one you need):
- [SQL Server connection pooling (ADO.NET)](https://learn.microsoft.com/en-us/sql/connect/ado-net/sql-server-connection-pooling): how pooling works and the tuning keywords.
- [EF Core connection resiliency](https://learn.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency): `EnableRetryOnFailure` and execution strategies.
- [SqlConnection connection string keywords](https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlconnection.connectionstring): the full keyword table including pooling and retry.
If the **Microsoft Learn MCP** server is configured, use `mcp__microsoft-learn__microsoft_docs_search` or `mcp__microsoft-learn__microsoft_docs_fetch` to fetch the current version of any of these on demand. It is optional; when it is unavailable, the references above are authoritative.More DevOps & Infrastructure skills
azure-ai
microsoft/azure-skills
Use for Azure AI: Search, Speech, OpenAI, Document Intelligence. Helps with search, vector/hybrid search, speech-to-text, text-to-speech, transcription, OCR. WHEN: AI Search, query search, vector search, hybrid search, semantic search, speech-to-text, text-to-speech, transcribe, OCR, convert text to speech.
appinsights-instrumentation
microsoft/azure-skills
Guidance for instrumenting webapps with Azure Application Insights. Provides telemetry patterns, SDK setup, and configuration references. WHEN: how to instrument app, App Insights SDK, telemetry patterns, what is App Insights, Application Insights guidance, instrumentation examples, APM best practices.
azure-storage
microsoft/azure-skills
Azure Storage Services including Blob Storage, File Shares, Queue Storage, Table Storage, and Data Lake. Answers questions about storage access tiers (hot, cool, cold, archive), when to use each tier, and tier comparison. Provides object storage, SMB file shares, async messaging, NoSQL key-value, and big data analytics. Includes lifecycle management. USE FOR: blob storage, file shares, queue storage, table storage, data lake, upload files, download blobs, storage accounts, access tiers, storage tiers, hot cool cold archive, storage tier comparison, when to use storage tiers, lifecycle management, Azure Storage concepts. DO NOT USE FOR: SQL databases, Cosmos DB (use azure-prepare), messaging with Event Hubs or Service Bus (use azure-messaging).

