Two Users, One Password, Two Completely Different Hashes

Imagine a website with two users who both, unimaginatively, choose the password "password123". Without a salt, hashing that password produces the exact same output both times, since a hash function always returns identical output for identical input. If an attacker steals the database, they see two identical hash values and instantly know both accounts share a password, and cracking one cracks both.

Now add a salt, a random value generated uniquely for each password before it's hashed:

User A: hash("password123" + "x7Fq2mZ9") = 8a1b3c...
User B: hash("password123" + "9kLp4WnR") = f2e9d0...

Same password, completely unrelated-looking hashes. Neither the shared password nor the fact that it's shared is visible anywhere in the stored data anymore. That single change, mixing in a per-password random value before hashing, is what a salt does, and it quietly defeats an entire category of attack that would otherwise make stolen password databases catastrophically easy to crack in bulk.

The Attack Salt Was Invented to Kill: Rainbow Tables

Before salting was standard practice, attackers built rainbow tables: enormous precomputed lists mapping millions (or billions) of common passwords to their hash values, generated once, then reused forever against any stolen database. Steal a database of unsalted hashes, look each one up in the table, and passwords fall out instantly, no actual cracking required for anything on the common-password list. This is why old breaches of unsalted password databases could be "cracked" for millions of accounts within hours of leaking.

A salt breaks this completely. A rainbow table built against unsalted hashes is useless against salted ones, because the attacker would need a separate precomputed table for every possible salt value, which multiplies the storage requirement into practical impossibility. The attacker is forced back to cracking each password individually, from scratch, which is dramatically slower and often not worth the effort for accounts that don't matter enough. See our brute force guide for how slow that individual cracking actually is against a properly hashed password.

Why Storing the Salt in Plain Text Doesn't Weaken Anything

A detail that trips people up: the salt sits right next to the hash in the database, unencrypted, visible to anyone who reads that row. This is not a bug. The salt's job was never to be secret.

A salt's entire value comes from being unique, not from being hidden. Its purpose is to guarantee that identical passwords produce different hashes, forcing an attacker to redo the expensive cracking work for every single account rather than solving all of them at once with a shared table. An attacker who has the salt still has to run a full password-guessing attempt against that one specific hash. Knowing the salt doesn't shortcut that process at all; it just lets them verify a guess is correct once they've made one. This is precisely why the salt can sit in plain text next to the hash without giving anything away.

Salt Versus Pepper: The Difference That Actually Matters

A related but distinct concept is the "pepper": also an extra value mixed in before hashing, but unlike a salt, a pepper is kept secret and stored separately from the password database entirely, often in application configuration or a hardware security module rather than the database itself. The distinction is simple once stated plainly:

  • Salt: unique per password, not secret, stored alongside the hash. Defeats rainbow tables and hides password reuse between accounts.
  • Pepper: shared across all passwords (or occasionally rotated), kept secret, stored apart from the database. If the database leaks but the pepper doesn't, the attacker is missing a piece they can't recover from the leak alone.

Careful implementations use both: salt to defeat bulk lookup attacks, pepper as a second line of defense in case the database itself is exposed but the application's configuration isn't.

Where Salting Actually Happens Today

Almost nobody implements salting by hand anymore, and that's by design. Modern password hashing algorithms, bcrypt, scrypt, and Argon2 being the names worth recognizing, generate and manage a unique salt automatically for every password, and are also deliberately slow, tunably so, specifically to make brute-force cracking expensive even on modern hardware. Compare that to fast, general-purpose hash functions like MD5 or plain SHA-256, which were built for speed and integrity checking, not for resisting a determined attacker with a stolen database and a GPU cluster. If you are a developer touching authentication code, the rule is short: never write your own salting logic, and never use a fast general-purpose hash for passwords. Use a purpose-built password hashing algorithm and let it handle salting for you.

What This Means If You're Not a Developer

Salting happens entirely server-side and invisibly to you as a user. You cannot inspect whether a site salts its password storage correctly, and that uncertainty is exactly why unique passwords per site matter so much. If one poorly built site suffers a breach with weak or absent salting, and you reused that password elsewhere, the damage spreads to every other account sharing it. A password manager or our password generator makes unique passwords for every site painless, and pairing that with 2FA means even a fully cracked password isn't enough to get in.

Frequently Asked Questions

If an attacker can see the salt, how does it protect anything?

Because the salt was never meant to be secret. Its job is to make every hash unique so that no precomputed table can match against it in bulk. An attacker with the salt still must crack that individual password from scratch; the salt doesn't hand them a shortcut, it just removes their ability to reuse work across accounts.

Does salting protect a genuinely weak password?

Only against bulk, shared attacks. A salted "123456" is still crackable on its own in essentially no time, since it's the first guess any cracking tool tries. Salt prevents that weak password from being cracked instantly alongside a million others; it does nothing to make the password itself stronger. That job belongs to length and randomness, covered in our password entropy guide.

Should every single password get its own unique salt, or can salts be shared?

Every password should get its own unique salt, and modern hashing algorithms handle this automatically per password. A salt shared across all users would still let an attacker build one precomputed table for that specific salt value and reuse it against the whole database, largely undoing the protection.

Is salting the same thing as encrypting a password?

No, and this distinction matters. Salting is used with hashing, a one-way process built for password storage, where the point is never to recover the original password, only to verify a login attempt matches. Encryption is reversible with a key, built for data you need to read back later. Passwords are never decrypted on a well-built site; they're re-hashed with the stored salt and compared.

As a regular user, is there anything I need to do about salting myself?

No, salting is entirely the website's responsibility and happens server-side where you can't see it. Your actual leverage is choosing a long, unique password for every account and turning on 2FA, so that even a site with weak password storage practices can't cause damage that spreads beyond that one account.

Shoyeb Akter

Written by

Security Tools Developer and creator of 2FA Fast, a privacy-first browser-based authenticator and security tools platform.