Security 2026-04-16

Fix Password Hashing & Bcrypt Verification Errors

Debug password hashing failures: bcrypt cost factor issues, salt generation problems, hash comparison errors, and migration from MD5/SHA to bcrypt.

bcrypt not working password hash mismatch bcrypt verification failed password hashing error

Password hashing errors can lock users out of their accounts or, worse, leave passwords vulnerable to attack. This guide covers common password hashing pitfalls, from bcrypt cost factor issues to timing-safe comparison failures.

Common errors covered

  1. 1 Comparing plaintext password to hash (always fails)
  2. 2 Bcrypt cost factor too high (hashing takes too long)
  3. 3 Timing-unsafe hash comparison
1

Comparing plaintext password to hash (always fails)

Error message
Login always fails even with correct password password !== storedHash is always true
Root cause

A common beginner mistake: comparing the plain password string directly to the bcrypt hash string. You must use the bcrypt verify function, which hashes the input with the same salt and compares the results.

Step-by-step fix

  1. 1 Never use === or == to compare a password to a hash.
  2. 2 Use the bcrypt library compare function: bcrypt.compare(password, hash).
  3. 3 Generate a test hash with our Hash Generator to understand the format.
  4. 4 Verify your database stores the full bcrypt hash (starts with $2b$).
Wrong
// WRONG: direct string comparison
if (password === storedHash) {
  // This NEVER works
}
Correct
// CORRECT: use bcrypt.compare()
const isValid = await bcrypt.compare(password, storedHash);
if (isValid) {
  // Password matches!
}

2

Bcrypt cost factor too high (hashing takes too long)

Error message
Request timeout: password hashing took > 30 seconds Server: 503 Service Unavailable during login
Root cause

Bcrypt cost factor is exponential: cost 10 is about 100ms, cost 12 is about 400ms, cost 15 is about 3.5s, cost 20 is about 2 minutes. A cost factor that is too high causes request timeouts.

Step-by-step fix

  1. 1 Check your current bcrypt cost factor (rounds).
  2. 2 Use cost factor 10-12 for web applications (100-400ms per hash).
  3. 3 Run a benchmark: time how long hashing takes on your production hardware.
  4. 4 Use our Password Generator to create strong passwords that compensate for a lower cost factor.
Wrong
// Cost factor 18 = ~45 seconds per hash!
const hash = await bcrypt.hash(password, 18);
Correct
// Cost factor 12 = ~400ms - good balance
const hash = await bcrypt.hash(password, 12);

3

Timing-unsafe hash comparison

Error message
Security audit: hash comparison is vulnerable to timing attacks
Root cause

Using simple string comparison for hash verification leaks timing information. An attacker can determine how many characters match based on response time, gradually guessing the hash.

Step-by-step fix

  1. 1 Replace === with a constant-time comparison function.
  2. 2 In Node.js: use crypto.timingSafeEqual().
  3. 3 In Python: use hmac.compare_digest().
  4. 4 For bcrypt: the library compare function is already timing-safe.
Wrong
// Timing-unsafe comparison
if (computedHash === storedHash) { ... }
Correct
// Timing-safe comparison
const a = Buffer.from(computedHash);
const b = Buffer.from(storedHash);
if (crypto.timingSafeEqual(a, b)) { ... }

Prevention Tips

  • Always use bcrypt, scrypt, or Argon2 for password hashing - never MD5 or SHA.
  • Use the bcrypt library built-in compare function instead of manual comparison.
  • Benchmark your cost factor on production hardware - aim for 100-400ms per hash.
  • Generate strong passwords with our Password Generator.

Frequently Asked Questions

Is SHA-256 safe for password hashing?

No. SHA-256 is a fast hash designed for data integrity, not password hashing. It can be brute-forced at billions of hashes per second. Use bcrypt, scrypt, or Argon2 which are deliberately slow.

How do I migrate from MD5 to bcrypt?

On next login: verify the old MD5 hash, then re-hash the plaintext password with bcrypt. Store the new hash. Add a flag to track which algorithm each user hash uses.

What password length should I require?

Minimum 8 characters, but 12+ is recommended. Do not set a maximum below 128 characters. Focus on preventing common passwords (use a blocklist) rather than complex character requirements.

Related Error Guides

Related Tools

Still stuck? Try our free tools

All tools run in your browser, no signup required.