Skip to content
MySQL Error 1819: Password Policy Requirements

Click to use (opens in a new tab)

MySQL Error 1819: Password Policy Requirements

November 3, 2026 by Chat2DBChat2DB Team

You run a simple CREATE USER, and MySQL rejects the password:

CREATE USER 'app'@'%' IDENTIFIED BY 'password123';
ERROR 1819 (HY000): Your password does not satisfy the current policy requirements

MySQL error 1819 comes from the validate_password component, which checks every new password against a policy. The message is frustratingly vague: it does not say which rule you broke. Fortunately, the rules are easy to read, and there is a function that scores a password before you try it.

The right response is usually a stronger password, not a weaker policy. This guide shows how to find the exact rules, why a given password failed, when it is reasonable to change the policy, and what the mistakes look like. The tests used MySQL 8.4.11 in Docker.

Why You See This Error

validate_password is optional. The official Docker image does not enable it, but it is often turned on by Linux packages, by mysql_secure_installation, or by a DBA. That is why the same script can work on one server and fail on another.

The check runs whenever MySQL sees a plain-text password, as in CREATE USER ... IDENTIFIED BY and ALTER USER ... IDENTIFIED BY. It also applies to the SET PASSWORD statement. To confirm whether it is active, look for it in the component table:

SELECT * FROM mysql.component;
+--------------+--------------------+------------------------------------+
| component_id | component_group_id | component_urn                      |
+--------------+--------------------+------------------------------------+
|            1 |                  1 | file://component_validate_password |
+--------------+--------------------+------------------------------------+

Step 1: Read the Current Policy

All the rules are system variables:

SHOW VARIABLES LIKE 'validate_password%';
+-------------------------------------------------+--------+
| Variable_name                                   | Value  |
+-------------------------------------------------+--------+
| validate_password.changed_characters_percentage | 0      |
| validate_password.check_user_name               | ON     |
| validate_password.dictionary_file               |        |
| validate_password.length                        | 8      |
| validate_password.mixed_case_count              | 1      |
| validate_password.number_count                  | 1      |
| validate_password.policy                        | MEDIUM |
| validate_password.special_char_count            | 1      |
+-------------------------------------------------+--------+

The policy value decides which of the other settings count:

PolicyRules
LOW (0)Length only
MEDIUM (1)Length, plus a digit, lowercase, uppercase and a special character
STRONG (2)MEDIUM, plus no substring found in the dictionary file

So under the default MEDIUM policy, password123 fails for two reasons: it has no uppercase letter and no special character. It has 11 characters, so length is not the problem.

Step 2: Score the Password Before You Use It

VALIDATE_PASSWORD_STRENGTH returns a number from 0 to 100. A failed attempt costs you nothing with this function, because it does not touch any account:

SELECT VALIDATE_PASSWORD_STRENGTH('password123') AS weak,
       VALIDATE_PASSWORD_STRENGTH('Abcd1234!') AS meets_medium,
       VALIDATE_PASSWORD_STRENGTH('Tr0ub4dor&3xtra') AS long_one;
+------+--------------+----------+
| weak | meets_medium | long_one |
+------+--------------+----------+
|   50 |          100 |      100 |
+------+--------------+----------+

A score of 50 means the password passes LOW but not MEDIUM. 100 means it passes the STRONG tests that are configured, which with an empty dictionary file means it meets the MEDIUM rules. Note the limit of this score: Abcd1234! gets 100, and it is a terrible password. The component checks the composition of a password, not how guessable it is, so use a generator rather than treating 100 as proof of quality.

Step 3: Use a Password That Passes

This is the fix in most cases. The statement that failed works with a password that meets the rules:

CREATE USER 'app'@'%' IDENTIFIED BY 'Abcd1234!';
Query OK, 0 rows affected

In practice, generate a long random password with a secrets manager or a tool such as openssl rand -base64 24. Be aware that a Base64 string does not always contain a special character. Add one, or set validate_password.special_char_count to suit your tooling.

Scripts need one more check. If a provisioning script generates passwords, make it follow the policy too, or it will fail at random, only when a generated value happens to lack a digit.

Step 4: Change the Policy Only if You Have a Reason

On a laptop or a disposable test database, a lower policy is reasonable. You need the SYSTEM_VARIABLES_ADMIN privilege, or the older SUPER:

SET GLOBAL validate_password.policy = LOW;
SET GLOBAL validate_password.length = 8;
 
CREATE USER 'app2'@'%' IDENTIFIED BY 'password123';
Query OK, 0 rows affected

SET GLOBAL lasts until the next restart. To keep the setting, use SET PERSIST, which writes it to mysqld-auto.cnf, or put the value in my.cnf:

SET PERSIST validate_password.policy = LOW;
[mysqld]
validate_password.policy=LOW

Both worked in my test on a server with the component installed. SET PERSIST wrote the value to mysqld-auto.cnf, and a server started with this option reported LOW.

Think before doing this on a production server. If a policy exists there, someone probably had a reason for it, such as an audit requirement, and an application account with a weak password is exactly what the policy is meant to prevent.

Uninstalling the Component

If a development server should not have the check at all, you can remove it:

UNINSTALL COMPONENT 'file://component_validate_password';
 
CREATE USER 'app4'@'%' IDENTIFIED BY 'x';
Query OK, 0 rows affected

After this, SHOW VARIABLES LIKE 'validate_password%' returns nothing, and even a one-character password is accepted. To add it back, run INSTALL COMPONENT 'file://component_validate_password';. Again, this suits a development box, not a shared server.

Common Mistakes

Using the old variable names. MySQL 5.7 had a plugin with an underscore in its variable names. MySQL 8 uses a component with a dot. Old instructions copied from the internet fail on a current server:

SET GLOBAL validate_password_policy = LOW;
ERROR 1193 (HY000): Unknown system variable 'validate_password_policy'

The same error appears with the right name when the component is not installed: Unknown system variable 'validate_password.policy'. Use the dotted name, and check mysql.component to see which case you have.

Expecting the user name check to look at the new account. validate_password.check_user_name compares the password with the user of the current session, not the account you are creating. In my tests, running as root and creating a user whose password equaled the new name raised no error. Do not rely on this setting to catch that mistake.

Counting characters wrongly. Letters outside ASCII count by case, so é is a lowercase letter, and characters without case, such as 中, also count as lowercase. They are not special characters, while symbols such as € and emoji are. In testing, an emoji added 4 to the length rather than 1, so Aa1!🙂 passed a length of 8 even though it has only five characters. These are quirks, and they are not a reason to pick such passwords.

Quoting problems in shell scripts. If the password has $, ! or a quote, the shell may change it before MySQL sees it, and you get a mysterious policy failure for a password that looks fine. Pass values through a file or an environment variable.

What About Password Hashes?

validate_password can only check a password it can read. A statement that supplies a ready-made hash skips the check entirely. On a server with the MEDIUM policy active, the first statement below failed and the second succeeded, even though both set the password 1234:

CREATE USER 'weak'@'%' IDENTIFIED BY '1234';
-- ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
 
CREATE USER 'weakh'@'%' IDENTIFIED WITH caching_sha2_password AS 0x24412430...;
-- Query OK

The account logged in with 1234. This is by design, because the server cannot recover a password from its hash, but it is a real gap in the policy: anyone who can create accounts this way can sidestep it. So do not treat the policy as a complete control. If you create accounts from hashes, check the strength before hashing. Our free MySQL Password Hash Generator (opens in a new tab) reports the result of the LOW and MEDIUM rules alongside the hash. Those rules matched the real component on all 2,500 random passwords I tested, and nothing is sent to a server. If you need a hash to be rejected outright, restrict who holds the CREATE USER privilege.

Related Errors

Password work tends to surface a few other errors:

  • ERROR 1827: The password hash doesn't have the expected format. A statement used IDENTIFIED WITH ... AS with a value that is not a valid hash.
  • ERROR 1524: Plugin is not loaded. The account uses a plugin the server does not have. See MySQL error 1524.
  • ERROR 1045: Access denied. The password is wrong, or the account does not match. See MySQL error 1045.

Quick Checklist

  1. Run SHOW VARIABLES LIKE 'validate_password%' to see the policy.
  2. Compare your password with each rule, or use VALIDATE_PASSWORD_STRENGTH.
  3. Use a long, generated password that meets the policy.
  4. Lower the policy only on a server where that is an accepted decision.
  5. Use the dotted variable names on MySQL 8.0 and later.

Manage Users Without the Trial and Error

It is easier to get this right when the rules and the accounts are in front of you. In Chat2DB (opens in a new tab) you can run the checks above in a console, review mysql.user in a grid, and ask the AI assistant to draft a CREATE USER statement with the grants you need. You can also use it in the browser at app.chat2db.ai (opens in a new tab).