Random password generator
Passwords drawn uniformly from a 74-character alphabet, generated in your browser, with the true entropy shown under every constraint.
More options
What the standards actually require
NIST SP 800-63B-4 is the document most password advice claims to follow and most password advice misquotes. It says, verbatim: "Verifiers and CSPs SHALL require passwords that are used as a single-factor authentication mechanism to be a minimum of 15 characters in length." The widely repeated figure of 8 characters applies only where the password is one factor inside multi-factor authentication. If a password is the only thing standing between an attacker and the account, the minimum is 15.
The same document says, also verbatim: "Other composition requirements for passwords SHALL NOT be imposed." That is a prohibition on the familiar rule demanding an uppercase letter, a digit and a symbol. NIST also removes periodic expiry: passwords are to be changed on evidence of compromise, not on a calendar. What it requires instead is screening candidate passwords against lists of values known to be compromised in breaches.
Appendix A of the same publication names machine-generated random passwords as a more effective mitigation than composition rules. That is the honest case for a tool like this one: not that a generated password looks complicated, but that it is drawn uniformly from a space you can count, which is the only claim about password strength that can be checked.
| Policy | Minimum | Maximum | Composition rule | Periodic rotation |
|---|---|---|---|---|
| NIST SP 800-63B-4 | 15 single-factor, 8 inside MFA | 64 or more recommended | Forbidden | Forbidden |
| OWASP Authentication Cheat Sheet | 15, or 8 with MFA | 64 or more | Forbidden | Not required |
| PCI DSS v4.0.1 req 8.3.6 | 12, or 8 if unsupported | Not specified | Numeric and alphabetic | 90 days unless MFA |
| Microsoft Entra ID | 8 | 256 | 3 of 4 types, Unicode banned | No expiry on new tenants |
| Windows AD with Passfilt | 7 | 127 interactive | 3 of 5 categories | 42 days on legacy defaults |
| AWS IAM default policy | 8 | 128 | 3 of 4 types | Never expire |
| GitHub | 8 with a number and a lowercase, or 15 with anything | Not stated | Conditional on length | None |
| Not stated, 12 recommended | Not stated | ASCII only, no leading or trailing space | None |
The live conflict between NIST and PCI DSS
PCI DSS v4.0.1 requirement 8.3.6 has been in force since 31 March 2025. It mandates a minimum of 12 characters containing both numeric and alphabetic characters, falling back to 8 where a system cannot support 12. That is a composition requirement, and NIST SP 800-63B-4 says composition requirements SHALL NOT be imposed. Two current, widely cited standards give opposite instructions, and any tool that pretends otherwise is not being straight with you.
The conflict has a practical consequence that most generators ignore. Take a uniform 16-character password drawn from the 62-character alphanumeric alphabet. The probability that it contains no digit at all is (52/62) raised to the 16th power, which is 0.05995, or 6.0%. Roughly one password in seventeen would be rejected by a PCI class check, through no fault of its own.
So a compliance mode has to enforce the constraint rather than hope for it. This generator does that, and it tells you what the enforcement costs. If you are not in PCI scope, the better answer to the whole argument is length: 15 characters or more satisfies NIST outright, and a 15-character password from a mixed alphabet clears PCI without anyone needing to write a composition rule into a policy document.
If you are subject to both, generate at 15 characters or longer with all four classes required. That satisfies the PCI floor and the NIST minimum at the same time, and the entropy cost of the class constraint at that length is under half a bit.
Requiring a character class reduces entropy
This is the part almost nobody shows you. The familiar formula, entropy equals length times log2 of alphabet size, is only valid when every character is drawn independently and uniformly. A rule saying the password must contain at least one digit forbids some strings, so the set of possible outputs is smaller than N to the power L, and the true entropy is log2 of the count of valid strings, not L times log2(N).
That count comes from inclusion-exclusion over the four character classes. On the default alphabet of 74 characters, made of 26 uppercase, 26 lowercase, 10 digits and 12 symbols, the figures are below. The cost is small at long lengths and material at short ones, which is a useful thing to know before you turn the constraint on.
The implementation matters as much as the arithmetic. The common shortcut is to generate a string and then overwrite fixed positions with one character from each required class. That produces a non-uniform distribution with a positional pattern, and its real entropy is lower than either figure in the table. This tool instead generates a complete candidate, tests it against every required class and discards it entirely on failure. Rejection is uniform over the valid set, so the entropy is exactly the constrained figure. The rejected-draw column shows how often that happens.
| Length | Unconstrained bits | True bits with all four classes | Cost | Draws rejected |
|---|---|---|---|---|
| 8 | 49.68 | 48.54 | 1.13 bits | 54.4% |
| 12 | 74.51 | 74.02 | 0.49 bits | 29.0% |
| 16 | 99.35 | 99.11 | 0.24 bits | 15.5% |
| 20 | 124.19 | 124.06 | 0.13 bits | 8.3% |
NIST moved away from entropy scoring because estimating the entropy of a password a human invented is unreliable. That objection does not apply to a uniform machine-generated draw, where the count of possible outputs is exact and can be checked by anyone.
Length limits and banned characters that break generated passwords
A generated password fails in production for boring reasons far more often than cryptographic ones. Systems impose maximum lengths, ban character ranges, and sometimes truncate silently instead of refusing, which leaves you with an account whose password is not the one you saved. Microsoft Entra ID accepts up to 256 characters and rejects Unicode outright. Windows Active Directory allows 127 characters for interactive logon. The AWS IAM default policy stops at 128. Google requires ASCII and rejects a leading or trailing space.
The symbol set matters for the same reason. The default here is the twelve symbols !#$%*+-=?@^_ , chosen because every one of them appears in the Entra ID, Active Directory and OWASP allowed sets. Restricting to those twelve rather than the full 33 printable ASCII punctuation characters costs 5.3% of the per-character entropy, which one extra character more than recovers. AWS IAM does not list the question mark among its accepted non-alphanumeric characters, so an AWS-targeted set is eleven symbols and 73 characters total, at 6.1898 bits per character instead of 6.2095.
Two transport hazards are worth knowing about because they corrupt a correct password after generation. A plus sign in a URL query string decodes to a space, so a password pasted into an unencoded link can arrive different from the one you sent. And a password beginning with an equals sign, a plus, a hyphen or an at sign is interpreted as a formula when a CSV file is opened in Excel or Google Sheets, which is a genuine injection vector as well as a corruption one. Our CSV export quotes every field, but the tool that reads the file decides what to do with it.
- Test the password against the target system before you save it anywhere.
- If the field truncates without warning, the stored password is the truncated prefix, and the entropy is the entropy of that prefix.
- A password manager entry is worth more than a memorable password, because it removes the length ceiling you impose on yourself.
How this generator works, and what we do not claim
Every character comes from crypto.getRandomValues, which is the browser interface to the operating system CSPRNG. Math.random is banned across this repository and the ban is enforced by a lint rule and a build-time grep over the shipped bundles. Indices are produced by rejection sampling against the largest multiple of the alphabet size below 2 to the power 32, because taking a raw 32-bit value modulo 74 would make some characters marginally more likely than others.
We do not claim to be more random than everyone else, because that claim would not survive scrutiny. Of fifteen generators audited on the first page of Google, five use Math.random in their generator logic, two are textbook-correct, and seven generate on a server with a legitimate source. Correct rejection sampling is table stakes and at least two competitors already ship it.
What we claim is narrower and checkable. The algorithm is published rather than described. The entropy shown is the real figure under whatever constraints you have enabled, including the constrained values above. And nothing generated here crosses the network: open the Network tab and generate, and it stays empty. That last point separates this page from the server-side generators, where the password exists in a request or response body and in whatever logs sit behind it.
Doing this in your own code
JavaScript
// 74-character alphabet: A-Z a-z 0-9 and the 12 safe symbols.
const ALPHABET =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%*+-=?@^_";
// Rejection sampling. v % n on a raw uint32 is biased whenever n does not
// divide 2^32, and 74 does not.
function pick(n) {
const limit = Math.floor(2 ** 32 / n) * n;
const buf = new Uint32Array(1);
let v;
do {
crypto.getRandomValues(buf);
v = buf[0];
} while (v >= limit);
return v % n;
}
function password(length = 20) {
let out = "";
for (let i = 0; i < length; i++) out += ALPHABET[pick(ALPHABET.length)];
return out;
} Math.random() is never acceptable here. V8 implements it with xorshift128+, whose internal state is recoverable from a handful of outputs.
Python 3.6+
import secrets
import string
ALPHABET = string.ascii_letters + string.digits + "!#$%*+-=?@^_"
def password(length: int = 20) -> str:
return "".join(secrets.choice(ALPHABET) for _ in range(length))
# With a required-class check, resample the WHOLE string on failure.
def password_all_classes(length: int = 20) -> str:
while True:
p = password(length)
if (any(c.isupper() for c in p) and any(c.islower() for c in p)
and any(c.isdigit() for c in p)
and any(c in "!#$%*+-=?@^_" for c in p)):
return p secrets.choice draws through randbelow, which rejection samples. random.choice rejection samples too, but it runs on the Mersenne Twister and must not be used for a password.
Go
import (
"crypto/rand"
"math/big"
)
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%*+-=?@^_"
func Password(n int) (string, error) {
b := make([]byte, n)
max := big.NewInt(int64(len(alphabet)))
for i := range b {
v, err := rand.Int(rand.Reader, max)
if err != nil {
return "", err
}
b[i] = alphabet[v.Int64()]
}
return string(b), nil
} crypto/rand.Int rejection samples internally. math/rand is seeded and predictable, and importing the wrong one is a common review miss.
PHP 7+
$alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%*+-=?@^_';
$n = strlen($alphabet);
$password = '';
for ($i = 0; $i < 20; $i++) {
$password .= $alphabet[random_int(0, $n - 1)];
} random_int throws rather than falling back to a weak source. rand() and mt_rand() are not suitable for credentials.
Java
import java.security.SecureRandom;
static final String ALPHABET =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%*+-=?@^_";
static String password(int length) {
SecureRandom rnd = new SecureRandom();
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i++) {
sb.append(ALPHABET.charAt(rnd.nextInt(ALPHABET.length())));
}
return sb.toString();
} nextInt(bound) rejection samples. Do not build one from nextDouble or from nextInt() % n.
C# / .NET 8+
using System.Security.Cryptography;
const string Alphabet =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%*+-=?@^_";
string Password(int length) =>
new string(RandomNumberGenerator.GetItems<char>(Alphabet, length)); RandomNumberGenerator.GetItems arrived in .NET 8 and is unbiased. On older targets, loop over GetInt32(0, Alphabet.Length).
Shell
# tr discards every byte outside the set, which is rejection sampling by
# construction. The hyphen must stay last inside the bracket.
LC_ALL=C tr -dc 'A-Za-z0-9!#$%*+=?@^_-' < /dev/urandom | head -c 20; echo
# A 192-bit token, if you do not need a typeable password. 24 bytes is
# 32 base64 characters with no padding, in the standard +/ alphabet.
openssl rand -base64 24 Without LC_ALL=C, tr in a UTF-8 locale can behave differently on high bytes.
Questions
How long should a password be?
If it is the only authentication factor, at least 15 characters, because NIST SP 800-63B-4 states that as a SHALL. If it is one factor inside multi-factor authentication, 8 is permitted by the same document. If you are storing it in a password manager and never typing it, there is no ergonomic reason to stop at the minimum, so 20 is a reasonable default and is what this page ships.
Should I still be requiring an uppercase letter, a digit and a symbol?
NIST says no: "Other composition requirements for passwords SHALL NOT be imposed." The rule exists to force variety out of human-chosen passwords, and it mostly produces predictable substitutions instead. It is irrelevant for a uniform random draw, which already uses the whole alphabet. The one reason to enable the constraint here is that a system you do not control demands it, which is common, so the toggle exists and reports what it costs.
Do I need to change my passwords every 90 days?
Not under NIST SP 800-63B-4, which requires a change only on evidence of compromise. PCI DSS v4.0.1 still requires 90-day rotation for in-scope accounts unless multi-factor authentication is in place, so the answer depends on which regime applies to the system. Forced rotation on a schedule is the reason so many passwords end with an incrementing number.
Is a password generated here ever sent anywhere?
No. Generation happens in the page, in your browser, using the operating system random source. There is no request, no logging and no storage. You can verify it rather than take it on trust: open the browser Network tab, generate, and watch nothing appear.
Why is the entropy shown lower than length times log2 of the alphabet?
Because you have a class constraint switched on. Requiring at least one character from each selected class forbids some strings, which makes the output space smaller than N to the power L. The displayed figure is log2 of the count of strings that satisfy the constraint, computed by inclusion-exclusion. Switch the constraint off and the two numbers agree exactly.
How long would it take to crack one of these?
That depends far more on how the site stores it than on the password. With hashcat 6.2.6 on one RTX 5090, MD5 runs at 220.6 GH/s while bcrypt at cost 5 runs at 304.8 kH/s, a gap of nearly six orders of magnitude on identical hardware. The same secret can be days of work or geological time depending on a decision made by someone else. Length is the part you control, so buy margin with it.
Can I use one of these as an API key or a database password?
Yes, though for a machine-to-machine secret you usually do not need a typeable alphabet at all. A hexadecimal or base64url token is easier to handle in configuration files and shell commands because it has no shell-significant characters. Use a password alphabet when a human or a legacy field is involved.