---
title: "SQL Server Password Generator (Meets CHECK_POLICY)"
description: "Generate SQL Server passwords that always pass CHECK_POLICY, right in your browser. Get CREATE LOGIN T-SQL, escaped connection strings and sa Docker setup."
image: "https://cdn.sethserver.com/blog-images/sql-server-password-generator-social-1789657430.webp"
---

# SQL Server Password Generator (Meets CHECK\_POLICY)

generating...

Password length (8 to 128)

Uppercase A-Z
 Lowercase a-z
 Digits 0-9
 Symbols !#$%&()\*+,-./:;<=>?@[]^\_{|}~
 Allow single quote (')

Login name

Database

### Create a login and database user

Run as a sysadmin (or a login with ALTER ANY LOGIN and rights in the database). The password is already escaped for T-SQL.

### Change an existing login's password

### Connection strings (password escaped)

First line: ADO.NET / Microsoft.Data.SqlClient. Second line: ODBC Driver 18.

## sa password for the Docker image

A separate password for `sa`, because the app login and sa should never share one. Same policy guarantees.

generating...

### Env file line (docker run --env-file sql.env)

Docker reads env files literally, so nothing needs escaping here.

### docker run (bash)

### docker-compose.yml

Compose treats `$` as the start of a variable, so each one is doubled.

### Change the sa password later

Both passwords are generated in your browser with `crypto.getRandomValues`. Nothing is sent to my server or stored. Change the options and the T-SQL, connection strings and Docker settings rebuild themselves.

SQL Server has an unusual quirk for a password generator: it will flat-out refuse a password that doesn't meet its policy, and the SQL Server Docker container will refuse to start. So "random" isn't enough. This generator only hands you passwords that pass, and then does the escaping for the three or four places the password has to go.

## The SQL Server password policy, exactly

SQL Server logins that use SQL Server authentication can use the Windows password policy mechanisms. `CHECK_POLICY` is `ON` by default in `CREATE LOGIN`. Microsoft Learn's "Password Policy" page lists the complexity rules as:

- The password doesn't contain the account name of the user.
- The password is at least eight characters long.
- The password contains characters from three of the four categories: uppercase letters A to Z, lowercase letters a to z, base 10 digits, and non-alphanumeric characters such as `!`, `$`, `#` and `%`.

With `CHECK_POLICY = ON`, SQL Server also refuses passwords that are empty, the same as the computer or login name, or one of `password`, `admin`, `administrator`, `sa` and `sysadmin`. Passwords can be up to 128 characters.

Here's how the generator guarantees a pass. It won't let you enable fewer than three character groups. It rejects and redraws any password that doesn't contain at least one character from every group you enabled, that contains the login name (compared case-insensitively), that matches one of the banned words, or that contains `$(` (more on that below). Redrawing the whole password, instead of patching in a required character at a fixed spot, keeps every allowed password equally likely.

I tested the edges on SQL Server 2022 in Docker. A 7-character password with all four groups fails with Msg 33062 ("too short"). `abcdefgh12`, with only two groups, fails with Msg 33064 ("not complex enough"), and so does `password`. A password containing the login name fails with the same 33064 error even when the letter case differs. `Abcdefgh12`, with three groups and no symbol, passes. One more detail: a two-character login name inside the password was accepted, so the generator only checks login names of three or more characters. That matches how Windows treats short account names.

One thing the policy check doesn't cover: `CHECK_EXPIRATION`. It defaults to `OFF` in `CREATE LOGIN`. For a service account I leave it off and rotate on my own schedule, because an application login that expires at 3am is an outage, not a security control. The generated T-SQL says `CHECK_EXPIRATION = OFF` explicitly so the next person reading it knows it was a decision.

## Single quotes, N'' and T-SQL escaping

In T-SQL a string literal is wrapped in single quotes, and a single quote inside it is written as two. The password `It's` becomes `N'It''s'`. The `N` prefix makes it a Unicode literal, which is harmless for ASCII and correct for everything else.

Microsoft's `CREATE LOGIN` page says passwords can't contain single quotes. In my test on SQL Server 2022, a login created with a doubled quote worked, and sqlcmd logged in with the raw password. It's still off by default here, because the places that break are the ones you don't control: deployment scripts that paste strings into SQL, config templating, and the occasional ORM migration. If you turn it on, the generated statements double every quote for you.

Double quotes and backslashes are never used. They cause more trouble in shells and connection strings than the entropy is worth.

## Where the password goes

The generated script creates a server-level login and then a database user mapped to it, with `db_datareader` and `db_datawriter`. That's the usual application setup: it can read and write tables but can't change schema, create logins, or read other databases. If the app only reads, drop the writer role. Schema changes belong to a separate migration login. I wrote more about why in [the principle of least privilege in the AI age](https://www.sethserver.com/ai/principle-of-least-privilege-in-the-ai-age.html).

If you paste the script into sqlcmd, or SSMS in SQLCMD mode, watch for `$(`. sqlcmd treats `$(name)` as a scripting variable anywhere in the script, including inside string literals. In my test, `N'ab$(x)cd'` printed "'x' scripting variable not defined" (and with `-b` the script exited with an error), and when a variable named `x` did exist, sqlcmd quietly replaced it and the string became `abZZcd`. That second case is the nasty one: you set a password that isn't the one you saved. The generator never produces `$(`. If you have an existing password that contains it, run sqlcmd with `-x` to turn off variable substitution.

## Connection strings: semicolons, quotes and braces

A password with a `;` in it splits a connection string in the wrong place. The two common formats escape differently:

| Format | Rule |
| --- | --- |
| ADO.NET (SqlClient) | A value containing `;`, `'` or `"` must be wrapped in double quotes. If it contains `"` but no `'`, wrap it in single quotes instead. A quote character that matches the wrapper is doubled. |
| ODBC Driver 18 | Wrap the value in braces: `PWD={...}`. A `}` inside the value is written as `}}`. |

The ADO.NET rule is from the `SqlConnection.ConnectionString` documentation, and the generator follows the same logic as `SqlConnectionStringBuilder`. The ODBC docs say that values in braces are passed to the driver intact, and older Native Client docs say a braced value can't contain a closing brace at all, so I tested the doubled `}}` form against SQL Server 2022 with pyodbc and ODBC Driver 18 before putting it on this page. It worked.

Honestly, the best escaping is the escaping you don't write. In .NET, build connection strings with `SqlConnectionStringBuilder`. In Python with pyodbc, keep the password out of the string you format by hand, or at least wrap it in braces as shown.

## SQL authentication vs Windows and Entra authentication

Everything above is about SQL Server authentication: a login name and password that SQL Server checks itself. Microsoft's guidance is blunt: "When possible, use Windows authentication." On Azure SQL the modern answer is Microsoft Entra ID with managed identities, where there's no password in your app at all. If your app runs on Azure, look there first.

SQL logins are still everywhere: Linux containers, apps outside the domain, vendor software, local development. On a Windows install, SQL logins only work if the server is in mixed mode ("SQL Server and Windows Authentication mode"); Windows Authentication mode turns SQL Server authentication off. Microsoft's docs also note that Azure SQL Database enforces password complexity.

## Contained database users

A contained database user has its own password stored in the database, with no server login behind it, so the user moves with the database instead of having to be recreated on each server. On SQL Server you have to allow it first:

```
EXEC sp_configure 'contained database authentication', 1;
RECONFIGURE;
ALTER DATABASE [AppDb] SET CONTAINMENT = PARTIAL;
GO
USE [AppDb];
CREATE USER [app_user] WITH PASSWORD = N'PASTE-GENERATED-PASSWORD';
ALTER ROLE db_datareader ADD MEMBER [app_user];
ALTER ROLE db_datawriter ADD MEMBER [app_user];
```

The same password policy applies to contained users with passwords (I checked: `abcdefgh12` gets the same Msg 33064). The connection string must name the database (`Database=AppDb`), because the user doesn't exist anywhere else. I ran this on SQL Server 2022 and logged in with sqlcmd using `-d AppDb`.

## The sa login and the Docker image

The Linux image reads the sa password from `MSSQL_SA_PASSWORD` (`SA_PASSWORD` is deprecated). Microsoft's quickstart says it must follow the password policy, and if it doesn't, the container can't set up SQL Server and stops. I confirmed that the unhelpful way: with a weak password the container exited a few seconds after starting, and `docker logs` said "ERROR: Unable to set system administrator password: Password validation failed."

Quoting is the other trap. In bash, double quotes still expand `$`, so `-e "MSSQL_SA_PASSWORD=Pa$$w0rd..."` silently sets a different password from the one you think you set. The generated `docker run` uses single quotes (with any `'` written as `'\''`). The env file is simpler: Docker reads each line literally. In a compose file, `$` starts variable interpolation, so it has to be written `$$`, which the generated snippet does.

Microsoft also notes that `MSSQL_SA_PASSWORD` is visible in `ps` output and in the container's environment, so change the sa password after first start. The generated `ALTER LOGIN [sa]` handles that.

Better still, stop using sa. Microsoft's guidance is to create a new login in the sysadmin role, connect with it, and disable sa:

```
CREATE LOGIN [dba_seth] WITH PASSWORD = N'PASTE-ANOTHER-GENERATED-PASSWORD', CHECK_POLICY = ON;
ALTER SERVER ROLE sysadmin ADD MEMBER [dba_seth];
GO
-- reconnect as dba_seth, then:
ALTER LOGIN [sa] DISABLE;
ALTER LOGIN [sa] WITH NAME = [not_sa_anymore];
```

Renaming sa doesn't make it safe on its own, but it does make every script that blindly guesses "sa" fail before it gets to guessing passwords.

## Generate a SQL Server password offline

These use the operating system's CSPRNG. Base64 output contains uppercase, lowercase and digits, so at this length it passes the complexity rule in practice, but it can in rare cases miss a group, so check it (or just use the generator above).

```
# PowerShell 7+
[Convert]::ToBase64String([Security.Cryptography.RandomNumberGenerator]::GetBytes(32))

# openssl
openssl rand -base64 32

# Python
python3 -c "import secrets; print(secrets.token_urlsafe(32))"
```

## Common mistakes

- **Double quotes around the sa password in bash.** `$` gets expanded and the container gets a different password.
- **Unescaped semicolon in a connection string.** The rest of the password becomes a keyword SqlClient doesn't recognize.
- **Apps connecting as sa.** One leaked config file away from losing the whole server.
- **CHECK\_POLICY = OFF to make a weak password work.** That's the policy doing its job; fix the password instead.
- **Passwords on the sqlcmd command line.** `-P` lands in shell history. Leave it off and sqlcmd prompts.

A strong password is the easy part of database security. My book [Databases in the Era of AI](https://www.sethserver.com/books/databases-in-the-era-of-ai) argues that secrets are the easy 10% and insecure data flow is the rest, and that's where most of the real damage happens.

## SQL Server password FAQ

What are the SQL Server password requirements?

When CHECK\_POLICY is ON, which is the default for CREATE LOGIN, SQL Server applies the Windows password policy. Under the complexity policy the password must be at least 8 characters, must not contain the login name, and must use characters from at least three of four groups: uppercase letters, lowercase letters, digits, and non-alphanumeric characters. It also rejects empty passwords and the words password, admin, administrator, sa and sysadmin. SQL Server passwords can be up to 128 characters.

How do I put a single quote in a SQL Server password?

Inside a T-SQL string literal a single quote is written as two single quotes, so the password It's becomes N'It''s'. The CREATE LOGIN documentation says passwords cannot contain single quotes, although in my test on SQL Server 2022 a doubled quote worked. Tools and scripts that build SQL by pasting strings together are exactly where it breaks, which is why this generator leaves single quotes out unless you turn them on.

What does MSSQL\_SA\_PASSWORD need for the SQL Server Docker image?

Microsoft says the MSSQL\_SA\_PASSWORD value must meet the SQL Server password policy: at least eight characters with characters from three of the four sets of uppercase letters, lowercase letters, digits and symbols. If it does not, the container cannot set up SQL Server and stops, and docker logs shows why. The older SA\_PASSWORD variable is deprecated.

How do I escape a password in a SQL Server connection string?

For ADO.NET (SqlClient), a value that contains a semicolon, single quote or double quote must be wrapped in quotes. Wrap it in double quotes, and if it contains double quotes but no single quotes, single quotes work instead. For ODBC, wrap the value in braces, as in PWD={...}. Microsoft ODBC Driver 18 accepts a closing brace inside the value when it is doubled. The simplest fix is a connection string builder class, which does the escaping for you.

Should I disable the sa login?

Yes, once you have another sysadmin login you can use. Microsoft recommends creating a new login in the sysadmin role and then disabling sa. ALTER LOGIN sa DISABLE turns it off and ALTER LOGIN sa WITH NAME renames it, which stops attacks that assume the name sa. Your applications should never connect as sa in the first place.

Is this SQL Server password generator safe?

The passwords are generated in your browser with crypto.getRandomValues and never leave the page. Nothing is sent to my server or stored. If policy requires generating production credentials on your own machines, the PowerShell and openssl commands on this page do the same job offline.

Related tools: [MongoDB Password Generator](https://www.sethserver.com/security/mongodb-password-generator.html), [Redis Password Generator](https://www.sethserver.com/security/redis-password-generator.html), [MySQL Password Generator](https://www.sethserver.com/mysql/mysql-strong-password-generator.html), [PostgreSQL Password Generator](https://www.sethserver.com/postgresql/postgresql-strong-password-generator.html), and the [general strong password generator](https://www.sethserver.com/security/strong-random-password-generator.html).

-Sethers


```json
{"@context": "https://schema.org", "@graph": [{"@type": "WebApplication", "applicationCategory": "DeveloperApplication", "author": {"@type": "Person", "name": "Seth Black", "url": "https://www.linkedin.com/in/seth-black-tx"}, "description": "Generate SQL Server passwords that always pass CHECK_POLICY complexity rules, with ready CREATE LOGIN, ALTER LOGIN and CREATE USER statements, escaped connection strings and MSSQL_SA_PASSWORD settings for Docker.", "name": "SQL Server Password Generator", "offers": {"@type": "Offer", "price": "0", "priceCurrency": "USD"}, "operatingSystem": "Web", "url": "https://www.sethserver.com/security/sql-server-password-generator.html"}, {"@type": "FAQPage", "mainEntity": [{"@type": "Question", "acceptedAnswer": {"@type": "Answer", "text": "When CHECK_POLICY is ON, which is the default for CREATE LOGIN, SQL Server applies the Windows password policy. Under the complexity policy the password must be at least 8 characters, must not contain the login name, and must use characters from at least three of four groups: uppercase letters, lowercase letters, digits, and non-alphanumeric characters. It also rejects empty passwords and the words password, admin, administrator, sa and sysadmin. SQL Server passwords can be up to 128 characters."}, "name": "What are the SQL Server password requirements?"}, {"@type": "Question", "acceptedAnswer": {"@type": "Answer", "text": "Inside a T-SQL string literal a single quote is written as two single quotes, so the password It's becomes N'It''s'. The CREATE LOGIN documentation says passwords cannot contain single quotes, although in my test on SQL Server 2022 a doubled quote worked. Tools and scripts that build SQL by pasting strings together are exactly where it breaks, which is why this generator leaves single quotes out unless you turn them on."}, "name": "How do I put a single quote in a SQL Server password?"}, {"@type": "Question", "acceptedAnswer": {"@type": "Answer", "text": "Microsoft says the MSSQL_SA_PASSWORD value must meet the SQL Server password policy: at least eight characters with characters from three of the four sets of uppercase letters, lowercase letters, digits and symbols. If it does not, the container cannot set up SQL Server and stops, and docker logs shows why. The older SA_PASSWORD variable is deprecated."}, "name": "What does MSSQL_SA_PASSWORD need for the SQL Server Docker image?"}, {"@type": "Question", "acceptedAnswer": {"@type": "Answer", "text": "For ADO.NET (SqlClient), a value that contains a semicolon, single quote or double quote must be wrapped in quotes. Wrap it in double quotes, and if it contains double quotes but no single quotes, single quotes work instead. For ODBC, wrap the value in braces, as in PWD={...}. Microsoft ODBC Driver 18 accepts a closing brace inside the value when it is doubled. The simplest fix is a connection string builder class, which does the escaping for you."}, "name": "How do I escape a password in a SQL Server connection string?"}, {"@type": "Question", "acceptedAnswer": {"@type": "Answer", "text": "Yes, once you have another sysadmin login you can use. Microsoft recommends creating a new login in the sysadmin role and then disabling sa. ALTER LOGIN sa DISABLE turns it off and ALTER LOGIN sa WITH NAME renames it, which stops attacks that assume the name sa. Your applications should never connect as sa in the first place."}, "name": "Should I disable the sa login?"}, {"@type": "Question", "acceptedAnswer": {"@type": "Answer", "text": "The passwords are generated in your browser with crypto.getRandomValues and never leave the page. Nothing is sent to my server or stored. If policy requires generating production credentials on your own machines, the PowerShell and openssl commands on this page do the same job offline."}, "name": "Is this SQL Server password generator safe?"}]}]}
{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "sethserver", "item": "https://www.sethserver.com/"}, {"@type": "ListItem", "position": 2, "name": "Tools", "item": "https://www.sethserver.com/tools/"}, {"@type": "ListItem", "position": 3, "name": "SQL Server Password Generator (Meets CHECK_POLICY)", "item": "https://www.sethserver.com/security/sql-server-password-generator.html"}]}
```
