How7o
  • Home
  • Tools
  • Prank Screens
  • Learn
  • Blog
  • Contact
Reading: Securely Hash Passwords in PHP (password_hash, Argon2id)
Share
How7oHow7o
Font ResizerAa
  • OS
Search
  • Home
  • Tools
  • Prank Screens
  • Learn
  • Blog
  • Contact
Follow US
© 2024–2026 How7o. All rights reserved.
How7o > Free Laravel, PHP, WordPress & Server Tutorials > Web Development > Securely Hash Passwords in PHP (password_hash, Argon2id)
Web Development

Securely Hash Passwords in PHP (password_hash, Argon2id)

how7o
By how7o
Last updated: May 23, 2026
6 Min Read
Securely hash passwords in PHP with password_hash
SHARE

To create a secure password hash in PHP, use the built-in password_hash function with PASSWORD_DEFAULT (bcrypt) or PASSWORD_ARGON2ID for the current cryptographic best practice. Never use MD5 or SHA — those are fast hashes built for files, not passwords. Verify on login with password_verify and re-hash old hashes when a stronger algorithm becomes available.

Contents
  • Hash and verify
  • Argon2id — the modern recommendation
  • Re-hash old hashes on login
  • Why MD5 / SHA-256 are wrong for passwords
  • Database column size
  • Frequently asked questions
  • Related guides
  • References

Last verified: 2026-05-17 on PHP 8.3. Originally published 2023-01-03, rewritten and updated 2026-05-17.

Hash and verify

// Registration / password change
$hash = password_hash($plaintext, PASSWORD_DEFAULT);
// Store $hash in the database (255 chars is a safe column size)

// Login
if (password_verify($plaintext, $hash)) {
    // Authentic — log the user in
} else {
    // Wrong password
}

PASSWORD_DEFAULT currently means bcrypt. PHP’s commitment is that this constant always points at the strongest algorithm shipped with that PHP version — using it future-proofs your code.

PHP password hashing — password_hash + verify, PASSWORD_DEFAULT bcrypt, Argon2id, password_needs_rehash

Argon2id — the modern recommendation

// PHP 7.3+
$hash = password_hash($plaintext, PASSWORD_ARGON2ID);

// Tunable options
$hash = password_hash($plaintext, PASSWORD_ARGON2ID, [
    'memory_cost' => 65536,   // 64 MB — RAM use
    'time_cost'   => 4,       // iterations
    'threads'     => 2,
]);

Argon2id won the 2015 Password Hashing Competition and is the current cryptographic best practice. It’s more resistant to GPU-accelerated brute force than bcrypt because it’s memory-hard — every guess requires significant RAM. The cost parameters above are sensible defaults; raise them if your hardware can handle slower hashes (server-side login is the only place this runs).

Re-hash old hashes on login

if (password_verify($plaintext, $user->password_hash)) {
    // Authenticate first

    if (password_needs_rehash($user->password_hash, PASSWORD_DEFAULT)) {
        $user->password_hash = password_hash($plaintext, PASSWORD_DEFAULT);
        $user->save();
    }

    // ... log in
}

When PHP upgrades the default algorithm (or you raise the cost), password_needs_rehash returns true for hashes that don’t match the current settings. Re-hashing during login (when you have the plaintext) upgrades active users transparently over time. Dormant users are still on the old algorithm, which is acceptable — they’re not the attack surface.

Why MD5 / SHA-256 are wrong for passwords

// DON'T DO THIS
$hash = md5($plaintext);                       // ~10 billion guesses/sec on a GPU
$hash = hash('sha256', $plaintext);            // billions/sec, same problem
$hash = sha1($plaintext . $salt);              // billions/sec, salted but still fast

MD5/SHA were designed for fast hashing of arbitrary data (signatures, integrity checks). That speed is a security bug when applied to passwords — an attacker with a stolen password table can try every word in every dictionary in hours. password_hash with bcrypt or Argon2id is intentionally slow (~100 ms per guess on standard hardware), turning a hours-long attack into one that takes years.

Database column size

$table->string('password', 255);   // safe ceiling for any algorithm

bcrypt produces a 60-character hash; Argon2id strings can be 96+. Use VARCHAR(255) to leave headroom for future algorithm upgrades without schema changes.

Frequently asked questions

Why is MD5/SHA-256 wrong for passwords?

Those are fast cryptographic hashes — designed for hashing files and signatures, where speed is a feature. For passwords, fast is the opposite of what you want: an attacker who steals the password file can brute-force billions of MD5 hashes per second on a GPU. password_hash uses bcrypt (or Argon2id), which is intentionally slow — billions of guesses per second drop to thousands.

How do I upgrade existing user passwords to a stronger hash?

Re-hash on next login. After verifying with password_verify, call password_needs_rehash($hash, PASSWORD_DEFAULT) — returns true if the stored hash uses an older algorithm than your current default. If yes, hash the plaintext (which you have during login) with the current default and update the row. Over time, every active user’s password gets upgraded transparently.

Should I salt manually?

No — password_hash generates a cryptographically random salt and embeds it in the result. The full hash string includes algorithm version, cost, salt, and the actual digest. You store one column and the salt comes along automatically. Manually salting (concatenating before hashing) used to be standard advice; the password_* API made it obsolete.

What’s the difference between bcrypt and Argon2?

Both are intentionally slow password-hashing functions. Bcrypt is older (1999), battle-tested, the current PHP default. Argon2id (PASSWORD_ARGON2ID, available since PHP 7.3) won the Password Hashing Competition in 2015 and is the current cryptographic recommendation — it’s more resistant to GPU/ASIC attacks via memory hardness. For new projects, Argon2id is the better pick; for compatibility with existing bcrypt hashes, stick with the default.

Related guides

  • How to Create a Login and Registration System in Laravel
  • How to Fix Missing Authorization Header in PHP Requests
  • How to Validate an Email Address in PHP

References

PHP password_hash: php.net/manual/en/function.password-hash.php. PHP password_verify: php.net/manual/en/function.password-verify.php. PHP password_needs_rehash: php.net/manual/en/function.password-needs-rehash.php. OWASP password storage cheat sheet: cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html.

TAGGED:AuthenticationphpSecurity

Sign Up For Daily Newsletter

Be keep up! Get the latest breaking news delivered straight to your inbox.
[mc4wp_form]
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Share This Article
Facebook Copy Link Print
Previous Article yum/dnf -y flag explained What Does the -y Flag Do in yum / dnf / apt-get?
Next Article Laravel old() helper for repopulating form inputs How Laravel’s old() Helper Works (and Why It Sometimes Doesn’t)
Leave a Comment

Leave a Reply Cancel reply

You must be logged in to post a comment.

FacebookLike
XFollow
PinterestPin
InstagramFollow
Most Popular
Set vi as the default editor in Ubuntu — a terminal opening the vim editor
How to Set vi (Vim) as the Default Editor in Ubuntu
June 8, 2026
rsync says ALL DONE but files are missing — a terminal showing ALL DONE next to an empty folder
rsync Says “ALL DONE” but Files Are Missing: How to Verify
June 8, 2026
Migrate a website to a new server with rsync — files copying from an old server to a new one over SSH
How to Migrate a Website to a New Server With rsync
June 8, 2026
Bun runtime — faster JS toolkit replacing npm in Laravel projects
How to Install Bun Runtime on Ubuntu (And Use It in a Laravel Project)
May 24, 2026
Tailscale mesh — peer-to-peer connections between devices, coordination server
How to Install Tailscale on Ubuntu (Zero-Config Mesh VPN for Self-Hosters)
May 24, 2026

You Might Also Like

Laravel Blade Time Format (HH:MM)
Web Development

How to Show Only Hours and Minutes in Laravel Blade (HH:MM)

3 Min Read
fail2ban shield blocking incoming brute-force probes, log file feeding the scanner
Server Management

How to Install fail2ban on Ubuntu (SSH, nginx, and WordPress Filters)

10 Min Read
Submit a form with jQuery
Web Development

How to Submit a Form Using jQuery

4 Min Read
Validate an email address in PHP with filter_var
Web Development

How to Validate an Email Address in PHP

5 Min Read
How7o

We provide tips, tricks, and advice for improving websites and doing better search.

Tools

  • Age Calculator
  • Word Counter
  • Image Upscaler
  • Password Generator
  • QR Code Generator
  • See all tools→

Pranks

  • Fake Blue Screen Prank
  • Hacker Typer
  • Fake iMessage Generator
  • Windows XP Crash Prank
  • Windows 11 Update Prank
  • See all prank screens →

Company

  • About Us
  • Blog
  • Contact
  • Privacy Policy
  • Terms of Service
  • Sitemap
© 2024–2026 How7o. All rights reserved.
Welcome Back!

Sign in to your account

Username or Email Address
Password

Lost your password?