What makes a password strong
One property: the number of equally likely passwords it could have been. That number is usually written as entropy in bits, and for a randomly generated password it is simple arithmetic: length × log2(pool size). Each character drawn from the full 90-character pool adds about 6.5 bits; each bit doubles the attacker's work.
The table shows what that means against a realistic worst case, a stolen database of fast hashes attacked by a small GPU rig at 10^12 guesses per second. The times are averages, half the keyspace.
| Password | Entropy | Cracked in |
|---|---|---|
| 8 chars, lowercase only | 37.6 bits | under a second |
| 8 chars, full pool | 51.9 bits | about 35 minutes |
| 12 chars, full pool | 77.9 bits | about 4,700 years |
| 16 chars, full pool | 103.9 bits | about 300 billion years |
| 20 chars, full pool | 129.8 bits | 10^19 years |
Two things follow. First, the jump from 8 to 12 characters matters more than any amount of symbol shuffling at length 8; adding four random characters multiplies the work by roughly 71 million, while swapping an a for an @ in a human-chosen password adds nearly nothing, because cracking tools try those substitutions first. Second, past 16 random characters you are buying astronomy, not security. We still default to 20: the two extra words of margin are free when a manager types for you, and stolen hashes get attacked years later on hardware that does not exist yet.
The arithmetic only holds for random generation. A password you invented is drawn from the much smaller space of things people invent, and tools like hashcat walk that space with wordlists and mangling rules before they ever brute-force. That is the entire reason a generator exists.
How to use this generator
The passwords are already there when the page loads. Click one to copy it, or hit regenerate for a fresh batch. Everything recalculates live as you move the length slider or toggle a set, and the four boxes below the tool always show the honest numbers for the current settings: entropy, pool size, and the average crack time against a throttled online attack and against an offline GPU rig.
- Set the rules. Length, character sets, and how many passwords you want at once (up to 100, downloadable as a .txt for seeding test accounts or a team vault).
- Pick one. A click copies it. Digits render green and symbols amber, so you can see at a glance what a site's form validator will be told about.
--all-sets
On by default. Guarantees at least one character from every enabled set, because that is what most signup forms demand and a purely random 12-character password misses at least one set about 28% of the time, usually the digits. Implemented without bias: the generator re-rolls the whole password until every set is present, instead of patching a symbol into a random position the way most generators do.
--no-lookalikes
Drops 0, O, 1, l, I and the pipe. In this page's monospace font they are distinguishable; on a sticky note, in a serif font or over the phone they are not. Turn it on for anything a human will retype, like a WiFi key.
--spell-it
Spells each password in the NATO alphabet, tango-alfa-seven-hash style, with capitals as UPPERCASE words. For the moment someone has to read a password to a colleague over a call, which happens more often than any of us would like.
exclude
Some sites refuse specific characters. Type them here and they leave the pool; the entropy readout drops accordingly, so you can see what the restriction costs and add length to compensate. The symbol set already omits quotes, backslash and space, the three characters that break login forms, CSV exports and shell scripts most reliably.
Where the randomness comes from
Every character is drawn with crypto.getRandomValues, the browser's interface to the operating system CSPRNG, the same source that generates TLS keys. Nothing about the generation touches the network: the page works with WiFi off, which you can and should verify, because it is the one claim about an online generator that is testable from the outside.
Two implementation details separate a correct generator from a sloppy one, and both are invisible in the UI. The first is modulo bias: mapping a random 16-bit value onto a 90-character pool with a plain modulo makes the first 46 characters of the pool slightly more likely, because 65536 is not a multiple of 90. The fix is rejection sampling, throwing away the top sliver of values and drawing again. The second is the every-set guarantee described above; patching a required character into a finished password concentrates probability on predictable positions, re-rolling does not.
Neither flaw is exploitable in practice at these entropy levels, and that is not the point. A generator whose authors did not handle the known pitfalls of uniform sampling is a generator you cannot judge on anything else either. The entropy figures shown here also account for the options honestly: with --all-sets active, the displayed bits are computed over the reduced space by inclusion-exclusion, not copied from the unconstrained formula.
The crack-time math, shown honestly
Most generators show a colored bar that turns green somewhere around 10 characters. A bar answers nothing. The two numbers under this tool are averages, computed as 2^(bits-1) guesses divided by a stated rate, and the rates are the interesting part:
| Scenario | Rate | Why this number |
|---|---|---|
| Online attack | 10/s | Guessing against the live login form. Rate limiting, lockouts and network latency cap the attacker; 10 per second is generous. |
| Offline, slow hash | ~2×10^5/s | Stolen database hashed with bcrypt: an RTX 4090 manages roughly 184,000 bcrypt guesses per second. Not shown in the stats, but the middle case worth knowing. |
| Offline, GPU rig | 10^12/s | Stolen database hashed with something fast: one RTX 4090 does about 164 billion MD5 guesses per second, a modest rig passes a trillion. |
The spread between the rows is the real lesson: the same password survives 10^14 years against the login form and an afternoon against a leaked MD5 table. You do not control which scenario applies, because you do not control how a site stores its hashes. The only variable you own is entropy, so pick a length that survives the worst row. Why fast hashes are the wrong tool for passwords, and what bcrypt and Argon2 do about it, is a story of its own; we wrote it up in our password hashing guide.
One honest caveat: these numbers assume the attacker must brute-force, which is only true for random passwords. Estimators that accept your existing password and rate it are answering a different, murkier question, and you should not type a real password into one anyway.
Composition rules, forced rotation and other myths
The rules most of us grew up with, one uppercase, one digit, change it every 90 days, came from a 2003 NIST document whose author has publicly said he regrets it. The current guidance, NIST SP 800-63B, reverses nearly all of it: verifiers should not impose composition rules, should not force periodic changes, should allow at least 64 characters, and should instead check candidates against known-breached password lists.
The reasoning is empirical. Composition rules push humans toward one pattern (capital first, digit and exclamation mark last, so Password1! satisfies everything), and cracking rule sets encode exactly that. Forced rotation produces incrementing suffixes, which attackers also model. Both rules make the password space smaller and more predictable while feeling like security.
For a random generator the rules are simply irrelevant: Kp3]wq@Zn7f{Ru2h meets any composition policy by accident, and rotation adds nothing to a secret that was never guessable. Keep --all-sets on because forms demand it, not because it strengthens anything, and spend your attention on length and uniqueness, the two properties that show up in the math.
The passwords you should never see
A generator page is the right tool at the edges: seeding test fixtures, a WiFi key, a shared appliance login, the account you create on a machine without your vault. For day-to-day accounts, the better workflow is generating inside a password manager, because the password then exists only inside the vault and autofill, and autofill quietly protects against phishing: the manager fills credentials on the exact origin it saved them for, and a lookalike domain gets nothing.
That leaves exactly one password a human still has to produce and remember, the vault's master password. Make it a passphrase of five to seven randomly chosen words rather than 20 random characters; at 12.9 bits per Diceware word, six words carry about 77.5 bits, enough against the key-stretched hashing every serious manager uses, and you can actually type it on a phone. Random character passwords for the hundreds of accounts, one long passphrase for the head. The passwords from this page fit the first category, and if you copied one to a clipboard-syncing OS, treat the clipboard as the leak vector it is and paste it promptly.
Generating passwords in the terminal
No browser needed when you live in a shell. All of these draw from the OS CSPRNG:
| Command | Notes |
|---|---|
openssl rand -base64 24 | 32 characters, about 144 bits before padding. Base64 means letters, digits, + and / only. |
LC_ALL=C tr -dc 'A-Za-z0-9!@#%^&*' </dev/urandom | head -c 20; echo | Full control over the pool. The LC_ALL=C matters on macOS, where tr otherwise dies on invalid UTF-8 with an illegal byte sequence error. |
pwgen -s 20 1 | The -s is the whole trick: without it pwgen produces pronounceable, meaningfully weaker passwords. Needs installing. |
python3 -c "import secrets; print(secrets.token_urlsafe(15))" | 20 URL-safe characters, 120 bits, available wherever Python is. |
The classic mistake in shell one-liners is piping /dev/urandom through filters that quietly shrink the pool, then trusting the length arithmetic of the original recipe. After editing a one-liner, recount: 20 characters from a 70-character pool is 122 bits, from hex it is 80. Where a browser page still wins over all of these is the moment you want the entropy math, the crack-time context and the batch download without writing the loop yourself.
Password questions
How long should a password be in 2026?
For a randomly generated password, 16 characters from a full character set, which is about 104 bits of entropy and beyond any realistic offline attack. The number that matters is who types it: a password your manager fills for you costs nothing at 20 or 24 characters, so there is no reason to stay at the minimum. Reserve shorter, memorable choices for the one or two secrets you must type from memory, and make those long passphrases instead. The old advice of 8 characters dates from a time when attackers checked passwords by logging in; against a stolen database and a modern GPU, 8 characters of any composition fall in hours.
How long does it take to crack an 8-character password?
Against a stolen database hashed with a fast algorithm like MD5 or NTLM, an 8-character password from the full 90-character set (about 52 bits) falls to a single RTX 4090 in a few hours, and to a small rig in about half an hour. Make it lowercase only and the answer is under a second, because 26^8 is only 209 billion combinations. The same 8 characters behind a rate-limited login form would survive for centuries, which is why the attack that matters is always the offline one: the attacker steals the hashes and guesses on their own hardware, with nothing throttling them.
What is password entropy and how is it calculated?
Entropy measures how many guesses an attacker needs in the worst case, expressed in bits: a password with n bits of entropy is one of 2^n equally likely possibilities. For a randomly generated password the formula is length × log2(pool size), so 12 characters drawn from 90 possible characters give 12 × 6.49 ≈ 78 bits. The formula only holds for random generation. A human-chosen password like Summer2026! has far less entropy than its length suggests, because attackers guess words, dates and substitution patterns first, and cracking tools like hashcat ship with rule sets that do exactly that.
Is it safe to use an online password generator?
Only if the generation happens in your browser and you can verify it. Most generator sites give no way to tell whether the password was produced locally or on their server, and a server that generates your password has seen your password. The checkable variant: open the page, switch the network off (flight mode or devtools offline), and generate again. If it still works, generation is local JavaScript and nothing you generate can leave the tab. This generator is built that way, calls crypto.getRandomValues directly, and keeps working offline. For high-value secrets the even safer habit is generating inside your password manager, which never involves a website at all.
Is Math.random() secure enough to generate passwords?
No. Math.random() is a statistical generator, not a cryptographic one: V8 (Chrome and Node.js) implements it as xorshift128+, whose entire internal state is 128 bits and can be recovered from a handful of consecutive outputs, after which every future output is predictable. It is also seeded without any security guarantee. Every mainstream runtime has a proper CSPRNG one call away: crypto.getRandomValues in the browser, crypto.randomInt or randomBytes in Node.js, secrets in Python, SecureRandom in Java. A password generator using Math.random() is broken by design, whatever its UI looks like.
How do I generate a secure random password in Python?
Use the secrets module, which draws from the operating system CSPRNG: import secrets, string; alphabet = string.ascii_letters + string.digits + string.punctuation; pw = "".join(secrets.choice(alphabet) for _ in range(20)). For URL-safe tokens, secrets.token_urlsafe(16) is one line and gives about 128 bits. The trap to avoid is the random module: random.choice and random.randint use a Mersenne Twister that is fully predictable after 624 observed outputs and is documented as unsuitable for security. secrets.choice also handles the uniform-selection problem correctly, so there is no modulo bias to worry about.
How do I generate a random password in JavaScript?
In the browser, crypto.getRandomValues fills a typed array from the CSPRNG; combine it with rejection sampling to pick characters uniformly, since taking a byte modulo the pool size skews toward the start of the pool whenever 256 is not an exact multiple. In Node.js, crypto.randomInt(0, pool.length) does the rejection sampling for you, and crypto.randomBytes gives raw material for tokens. Do not reach for Math.random() and do not shuffle with sort(() => Math.random() - 0.5), which is both insecure and biased. Web Crypto is available in every browser released since roughly 2014, so there is no compatibility reason to avoid it.
Which is better, a random password or a passphrase?
They solve different problems. A 20-character random password (about 130 bits) is stronger per character but impossible to remember, so it belongs to the accounts your password manager fills. A passphrase of six Diceware words (about 77.5 bits) is weaker per character but genuinely memorable and fast to type, which makes it the right shape for the few secrets that live in your head: the manager master password, full-disk encryption, your computer login. The failure mode is inventing the passphrase yourself; a sentence you thought of is drawn from language patterns, not from a uniform dictionary, and cracking tools model those patterns well. Roll the words randomly.
How often should I change my passwords?
When there is a reason: the service reports a breach, the password shows up in a leak, you typed it on a phishing page, or someone who knew it should no longer have access. Scheduled rotation without such a trigger is no longer recommended; NIST SP 800-63B has advised against arbitrary periodic changes since 2017, because forced rotation reliably produces Password1 becoming Password2 and post-its on monitors. A strong random password does not wear out. The useful habit is not rotation but monitoring: breach notifications from your password manager or haveibeenpwned tell you which single password actually needs replacing.
Why do some websites not allow special characters in passwords?
Almost always legacy caution, not security. Systems that once assembled SQL or shell commands from user input banned quotes and backslashes instead of fixing the escaping, and the ban outlived the bug by decades. Mainframe backends and old LDAP directories also choked on characters outside a narrow set. None of this is a reason a modern site needs, since a password should be hashed immediately and a hash does not care about characters. As a user you cannot fix it, only route around it: this generator has an exclude field for exactly these sites, and length compensates for the smaller pool at roughly 6.5 bits per extra character.
Why do some sites limit password length to 64 or 72 characters?
The 72 limit is bcrypt showing through: bcrypt only hashes the first 72 bytes of input and silently ignores the rest, so honest sites cap the field rather than accept characters that do nothing. Caps around 64 usually come from NIST SP 800-63B, which requires supporting at least 64 characters, so some forms allow exactly that minimum. Any limit below about 20 is a red flag with a different cause: it can mean the password is stored in a fixed-width database column, possibly not hashed at all. A random 20-character password is far beyond crackable anyway, so these caps cost real security only when they force you under 16.
Do I really need a different password for every account?
Yes, and reuse is the single most exploited password mistake. Credential stuffing works because billions of leaked email-password pairs are freely traded and tested against every major site by botnets; if one forum you registered on in 2015 was breached, that exact pair has been tried against your email provider, your bank and your Amazon account. The strength of the password is irrelevant here, since the attacker is not guessing it but replaying it. Unique random passwords make a breach of one site a non-event for the rest of your accounts, and a password manager is what makes unique-everywhere practical.