Skip to content

PHP Tutorial Authentication

Password Hashing

Lesson 282 of 369 3 min read By Deepak Paswan Updated Oct 5, 2026

If someone steals your database, what do they find in the password column?

What you storedWhat the thief gets
The password itselfEvery user’s real password
An unsalted fast hash (MD5, SHA-1, SHA-256)Most passwords, cracked in minutes, using ready-made tables and fast computers
A slow, salted password hashVery little. Each password must be guessed one at a time, slowly

The last row is the goal.

Hashing vs encryption

  • Encryption is two-way: you can lock and open the data with a key.
  • Hashing is one-way: you turn the data into a fixed-size fingerprint and cannot go back.

For passwords you want hashing. You never need to know the password. You only need to check whether the typed one matches.

index.php
PHP
<?php
echo hash("sha256", "secret") . "\n";
echo hash("sha256", "secret");
Output
OUTPUT
2bb80d537b1da3e38bd30361aa855686bde0eacd7162fef6a25fe97bf527a25b
2bb80d537b1da3e38bd30361aa855686bde0eacd7162fef6a25fe97bf527a25b

The same input always gives the same hash. That is also why plain sha256 is bad for passwords: an attacker can pre-compute hashes for millions of common passwords and just look yours up.

Salt

A salt is random data added to each password before hashing. With a salt, two users who choose secret get completely different hashes, and pre-computed tables become useless. The salt is stored together with the hash.

Slow on purpose

MD5 or SHA-256 can be computed billions of times per second on a graphics card. A good password hash is deliberately slow (and uses memory), so an attacker can only try a few guesses per second. bcrypt and Argon2 do this.

Never write this yourself

Do not invent your own scheme (md5($password . $salt), double hashing, a secret “pepper” in a custom formula). Cryptography is easy to get wrong. PHP has the right tool built in, and it handles salt, cost and format for you:

index.php
PHP
<?php
$hash = password_hash("secret", PASSWORD_DEFAULT);

var_dump(password_verify("secret", $hash));
var_dump(password_verify("Secret", $hash));
Output
OUTPUT
bool(true)
bool(false)

Things you should not use for passwords

FunctionWhy not
md5(), sha1(), sha256 and friendsToo fast, no salt handling
crypt() directlyEasy to misuse
Your own “encryption”Reversible, so a leak exposes every password
password_hash with a hand-made salt optionThe salt option was removed. PHP picks a safe salt itself

If you already have old hashes

Users with an old MD5 hash can be migrated: verify with the old method at their next login, then immediately re-hash with password_hash() and save the new value. password_verify() shows password_needs_rehash().

What hashing does not do

Hashing protects the passwords if the database leaks. It does not stop someone from guessing a weak password on your login form. You still need rate limiting, strong password rules and (for important accounts) two-factor authentication. See Authentication Security.

info
Why this matters in WordPress and Laravel
WordPress stores password hashes in wp_users (using its own portable hashing, and newer versions use bcrypt). Laravel hashes with bcrypt or Argon2 through its Hash facade. In both, you never see a plain password in the database.