What is Password Hashing?
Definition
Password hashing is the practice of storing user passwords not as plain text or reversible ciphertext, but as the output of a deliberately slow, one-way algorithm such as Argon2id, scrypt or bcrypt, combined with a unique random salt per password. At login, the submitted password is hashed the same way and compared with the stored value. The goal is to make guessing passwords from a leaked database as expensive as possible.
Also known as: password storage, salted password hashing, password salting, password salt

Verify, don't store
A login system never needs to know a user's password; it only needs to check whether the one just typed is correct. So passwords are not stored in plain text, and they are not encrypted either: encryption is reversible, and the key lives on the same infrastructure, so a breach can expose both. The right approach is to store a one-way digest, run the same algorithm at login, and compare.
Not just any hash function will do. OWASP's Password Storage Cheat Sheet is blunt about it: fast algorithms such as SHA-256 are unsuitable for passwords because they let attackers make enormous numbers of guesses quickly. Password hashing algorithms are slow on purpose.
Salts make every hash unique
A salt is a random value generated for each password and stored alongside its hash. Two users who pick the same password end up with different hashes because their salts differ. That defeats precomputed lookup tables (rainbow tables) and forces an attacker to crack each account separately rather than the whole table at once. A salt is not a secret; its job is uniqueness. Modern libraries generate the salt and embed it in the output automatically, so application code rarely handles it directly.
Slowness is the feature
Password hashing algorithms expose a tunable cost. A few hundred milliseconds is invisible to someone logging in, but it turns billions of guesses into an impractical job. Argon2id and scrypt are also memory-hard: they consume RAM as well as time, which blunts massively parallel attacks on GPUs and custom hardware. OWASP's current recommendations, in order of preference:
| Algorithm | OWASP minimum configuration |
|---|---|
| Argon2id | 19 MiB memory, 2 iterations, parallelism of 1 |
| scrypt | N = 2^17, r = 8, p = 1 |
| bcrypt | Work factor 10 or more; input limited to 72 bytes |
| PBKDF2 | 600,000 or more iterations with HMAC-SHA-256 (where FIPS compliance is required) |
These are floors, not targets; raise them as far as your servers comfortably allow. An Argon2id hash records the algorithm, parameters, salt and result in a single string:
$argon2id$v=19$m=19456,t=2,p=1$<salt (base64)>$<hash (base64)>Because the parameters travel with the hash, raising the cost later does not break existing records. When a user next logs in successfully, you can rehash their password with the new settings and update the stored value.
Peppers and legacy migrations
A pepper is an additional secret shared by all passwords and kept outside the database, in a secrets manager or hardware security module. An attacker who steals only the database cannot even start guessing without it. It is optional, but a worthwhile defence-in-depth layer.
Teams that inherit MD5 or unsalted SHA-1 hashes have two migration paths: rehash each password with a modern algorithm as users log in, or immediately wrap every legacy hash inside a modern algorithm and switch each account to a direct hash at its next login. The second path protects dormant accounts straight away instead of leaving them exposed indefinitely.
Part of login security, not all of it
Good hashing limits the damage after a breach. It does nothing to stop online brute-force attacks against the live login form; that takes rate limiting, checks against known breached passwords, and multi-factor authentication. Making sure passwords never end up in logs, error reports or analytics matters as much as the choice of algorithm.

