Compatibility guide

WordPress password hash formats, without the guesswork.

Use the prefix to identify the format, then choose the right recovery or migration path. This is a practical reference for the values you find in user_pass.

01New WordPress hashes start $wp$2y$.

They are bcrypt hashes with WordPress’s SHA-384 pre-hash and a $wp marker.

02Older $P$ hashes are still valid.

WordPress keeps phpass support so an upgrade does not lock users out.

03The prefix is a clue, not proof.

Plugins can use their own hashing logic, so always consider the site’s configuration.

What lives in user_pass?

WordPress does not store a reversible password. It stores a one-way value that can be checked when someone signs in. The same password will normally produce different stored values because password-hashing algorithms include a random salt. Treat both the password and its hash as sensitive: neither belongs in a ticket, screenshot, or public repository.

The beginning of the stored string is the quickest way to identify the normal verification path. The matrix below describes the formats you are most likely to encounter in a WordPress database.

PrefixMeaningWhat to do
$wp$2y$Current WordPress Core bcrypt formatUse the modern generator or let WordPress create it.
$P$Legacy portable phpassStill accepted; use only for a legacy-compatible reset.
$2y$ / $2b$Plain bcrypt, often plugin-createdVerify as normal bcrypt; do not add $wp yourself.
32 hex charsLegacy MD5An emergency fallback; change the password after signing in.

Current WordPress: why $wp$2y$ is not plain bcrypt

WordPress 6.8 made bcrypt the default for new user passwords. To preserve the full entropy of passwords longer than bcrypt’s 72-byte input limit, Core first creates a keyed SHA-384 HMAC and Base64-encodes it. It then bcrypts that resulting value and adds the $wp prefix.

1 Trim input2 HMAC-SHA-3843 Base644 bcrypt + $wp

This matters when a database value must be set manually: a plain $2y$ bcrypt hash is not the same as a current Core-created password hash. The modern hash generator follows this sequence and produces the stored $wp$2y$ value.

Legacy phpass: $P$

Before 6.8, WordPress’s standard password hasher produced a portable phpass value, usually beginning $P$. WordPress continues to verify these values so existing users can sign in after an upgrade. Once they change their password or log in under the current default flow, WordPress can replace the old value with a newer hash.

Use the legacy phpass generator when you know the target needs this format—for example, an older installation or a migration procedure that explicitly requires it. Do not choose it simply because it is familiar.

Plain bcrypt, MD5, and custom algorithms

A hash beginning $2a$, $2b$, or $2y$ is ordinary bcrypt without the WordPress $wp envelope. This can be legitimate when a plugin or integration generated the password. A 32-character hexadecimal value is commonly an old MD5 value; WordPress retains MD5 checking for backward compatibility, but it should be replaced after access is restored.

WordPress installations can also opt into another supported password algorithm, such as Argon2, or replace password handling through a plugin. That is why a prefix helps with identification but does not eliminate the need to understand the target site.

Before you paste a hash into a database

  1. Confirm that you are authorized to administer the site and have a current backup.
  2. Identify the WordPress version or expected format instead of guessing from a tutorial.
  3. Use the normal reset flow or WP-CLI when available; let WordPress create the value itself.
  4. Use the local verifier to test a hash only when necessary, then change the password through WordPress after recovery.

Primary references: wp_hash_password() and wp_check_password().