SQL Server Connection String Examples

The same six or seven key=value pairs, rearranged slightly for every auth method. Here's a working example of each, and the two settings that cause the most support tickets on Azure SQL.

reference guide SQL Server Azure SQL

// anatomy

│

A connection string is a semicolon-separated list of Key=Value pairs. Order doesn't matter, keys aren't case-sensitive, and most drivers tolerate a handful of alternate spellings for the same key (User Id / UID, Server / Data Source). What changes between the examples below is only which keys are present.

// sql authentication

│

A username and password stored on the SQL Server instance itself, independent of Windows or Azure AD accounts. Most common for on-prem servers and for services that shouldn't have a domain identity.

example
Server=tcp:myserver.database.windows.net,1433;Database=StoredValueDb;User Id=app_user;Password=***;Encrypt=True;

// windows / integrated authentication

│

The connecting process's Windows identity is passed through — no username or password in the string at all. Only works when the app and the SQL Server are on the same domain (or a trusted one), which rules it out for most cloud-hosted apps talking to Azure SQL.

example
Server=localhost\SQLEXPRESS;Database=StoredValueDb;Integrated Security=True;Encrypt=False;

// azure ad variants

three flavors
Defaulttries managed identity, then environment credentials, then a chain of fallbacks — the right choice for apps already running in Azure
Interactivepops a browser login prompt — for local development, never for a running service
Passworda literal Azure AD username/password in the string — works, but is being phased out in favor of the above two wherever possible
example (Active Directory Default)
Server=tcp:myserver.database.windows.net,1433;Database=StoredValueDb;Authentication=Active Directory Default;Encrypt=True;

// pooling keys most people never touch

│

Connection pooling is on by default — the driver keeps physical connections open behind the scenes and hands them out to your app rather than opening a fresh TCP+login for every request. Most apps never need to change the defaults, but these are the keys that matter when they do:

pooling keys
Poolingdefaults to true — set false only for diagnosing a pooling-related bug, never in production
Max Pool Sizedefaults to 100 — requests beyond this wait for a free connection instead of opening a new one, which is where "Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool" comes from
Min Pool Sizedefaults to 0 — set above 0 to keep a floor of warm connections ready instead of paying the first-connection cost after idle periods
Connection Lifetimedefaults to 0 (unlimited) — seconds before a pooled connection is torn down and reopened, useful for spreading load evenly across replicas behind a load balancer
That pool-timeout error is almost never "the pool is too small" — it's usually connections not being disposed (missing a using block around a SqlConnection) so the pool fills up with connections the app thinks it already returned. Raising Max Pool Size masks the symptom; it doesn't fix a connection leak.

// two timeouts that get confused constantly

connect timeout vs command timeout
Connect Timeouta connection-string key (default 15s) — how long to wait while establishing the TCP connection and logging in
Command Timeoutnot a connection-string key at all — it's SqlCommand.CommandTimeout in code (default 30s), how long to wait for one query to finish executing

Putting Command Timeout=60 in a connection string does nothing — it's silently ignored because no such key exists. A slow-running query needs the timeout raised on the SqlCommand (or DbCommand) object itself, per call, not in the connection string.

// MultipleActiveResultSets (MARS)

│

MultipleActiveResultSets=True lets more than one pending batch or open DataReader share a single physical connection at once — without it, opening a second command while a reader from the first is still open throws InvalidOperationException. It shows up most with older ADO.NET code that reads with one open SqlDataReader while issuing further queries on the same connection, or with EF6 lazy-loading during enumeration. It has a real cost — the server keeps more state per connection — so it's worth turning on only when the access pattern actually needs it, not as a default safety net.

// where the connection string actually lives in an ASP.NET Core app

│

Convention puts it under a ConnectionStrings section in appsettings.json, read via builder.Configuration.GetConnectionString("Default"). Everything past that is about not committing real credentials to source control:

by environment
local dev.NET user-secrets (dotnet user-secrets set) — keeps it out of the repo entirely, still resolved by the same configuration API
CI / containersan environment variable named ConnectionStrings__Default — the double underscore is deliberate, it's how ASP.NET Core's configuration binder maps env vars to the :-delimited key ConnectionStrings:Default
productionAzure Key Vault or a secrets manager, wired in as an additional configuration provider — never a real password in appsettings.json

Whichever source it comes from, the same validation applies before it reaches your app — check it with the appsettings.json Validator, which flags a plaintext connection-string password sitting in the file alongside the usual JSON syntax and duplicate-key checks. If the database this connects to is managed with EF Core migrations, a mismatched connection string is one more way Update-Database ends up confused about what's actually there.

// what trips people up on azure sql

Azure SQL rejects connections without Encrypt=True. It's not optional the way it is for an on-prem server — a connection string that works fine locally against SQL Express will fail outright against *.database.windows.net until this is set.
TrustServerCertificate=True skips certificate validation entirely — it's a workaround for a self-signed cert on a local dev instance, not something that belongs in a connection string pointed at a real Azure SQL server. Its presence there is usually a leftover from copy-pasting a local dev string.
Integrated Security and a User Id/Password in the same string don't combine — one wins silently depending on the driver, and it's easy to leave stale credentials in a string after switching an app to Windows auth without noticing they're now ignored.
Microsoft.Data.SqlClient 4.0 flipped the client-side default of Encrypt from false to true. A connection string that worked fine for years against an on-prem server with no valid cert can start failing after nothing more than a NuGet package upgrade — the fix is either a proper certificate or an explicit Encrypt=False/TrustServerCertificate=True for that environment, not a downgrade. The full breakdown covers this alongside the related "keyword not supported" error that shows up from mixing System.Data.SqlClient and Microsoft.Data.SqlClient.

// frequently asked questions

Why does Azure SQL reject my connection string that works fine locally?

Azure SQL rejects connections without Encrypt=True — it's not optional the way it is for an on-prem server. A connection string that works fine against a local SQL Express instance will fail outright against *.database.windows.net until that key is set.

What's the difference between Connect Timeout and Command Timeout?

Connect Timeout is a connection-string key (default 15s) — how long to wait establishing the TCP connection and logging in. Command Timeout isn't a connection-string key at all; it's SqlCommand.CommandTimeout set in code (default 30s), how long to wait for one query to finish. Putting Command Timeout=60 in a connection string does nothing — it's silently ignored.

Why am I getting "Timeout expired waiting for a connection from the pool"?

Almost never because the pool is too small — it's usually connections not being disposed (a missing using block around a SqlConnection), so the pool fills up with connections the app thinks it already returned. Raising Max Pool Size masks the symptom rather than fixing the leak.

Where should a SQL Server connection string be stored?

Convention puts it under a ConnectionStrings section in appsettings.json. For local dev, use dotnet user-secrets to keep it out of the repo. In CI/containers, an environment variable named ConnectionStrings__Default (the double underscore maps to the :-delimited key). In production, Azure Key Vault or a secrets manager — never a real password in appsettings.json.

What does MultipleActiveResultSets (MARS) actually do?

MultipleActiveResultSets=True lets more than one pending batch or open DataReader share a single physical connection at once. Without it, opening a second command while a reader from the first is still open throws InvalidOperationException. It has a real server-side cost, so it's worth enabling only when the access pattern actually needs it.

// try it yourself

│

Build a connection string for any of these auth methods, or paste an existing one to see it broken into fields (with the password masked), using the Connection String Builder — it also flags the Azure SQL/Encrypt mismatch above automatically. If a column in the same database stores Unix timestamps rather than DATETIME2, converting between the two in T-SQL has its own overflow gotcha worth knowing before it bites in production.