MySQL Password Generator
How to correctly generate and apply a secure password for a MySQL user account โ and why the database itself is the wrong place to generate it.
Generate the Password Outside the Database
Unlike a general-purpose programming language, SQL has no cryptographically secure random function. The correct workflow is: generate the password with a proper CSPRNG in your application, deployment script, or a generator like ours โ then apply it with a standard SQL statement.
-- Password generated externally with a CSPRNG, e.g. our Strong Password Generator
ALTER USER 'app_user'@'%' IDENTIFIED BY 'k7$Rt2Xz!mQ9wLp#4vNc';
-- Or when creating a new account
CREATE USER 'app_user'@'%' IDENTIFIED BY 'k7$Rt2Xz!mQ9wLp#4vNc';
FLUSH PRIVILEGES;
The Wrong Way (Don't Do This)
RAND() function. It is seeded from the system clock by default, statistically weak, and never intended for security-sensitive values.
-- INSECURE โ RAND() is not cryptographically secure
SELECT SUBSTRING(MD5(RAND()), 1, 16) AS weak_password;
This pattern is common in tutorials, but RAND()'s seed and internal state are far weaker than a real CSPRNG, and wrapping the output in MD5() does not add security โ it only obscures the weak input.
Scripting It End-to-End
A typical secure provisioning script generates the password in the calling language, then passes it into the SQL statement as a parameter โ never concatenated as a raw string:
import secrets, string
import mysql.connector
def generate_password(length=24):
alphabet = string.ascii_letters + string.digits + "!@#$%^&*()-_"
return "".join(secrets.choice(alphabet) for _ in range(length))
password = generate_password()
conn = mysql.connector.connect(host="localhost", user="root", password="...")
cursor = conn.cursor()
cursor.execute(
"ALTER USER %s@'%%' IDENTIFIED BY %s",
("app_user", password)
)
conn.commit()
# Store `password` in your secrets manager here โ do not print or log it.
Enforcing Password Strength in MySQL
MySQL's optional validate_password component can enforce minimum length and character-class requirements at the database level:
INSTALL COMPONENT 'file://component_validate_password';
SET GLOBAL validate_password.length = 16;
SET GLOBAL validate_password.policy = 'STRONG';
Common Mistakes
- Concatenating the password directly into a SQL string instead of using parameterised queries โ even for account creation scripts, always use bound parameters to avoid injection risk.
- Logging the generated password in application or deployment logs "for the record" โ send it to a secrets manager instead.
- Leaving
validate_passworddisabled in production, allowing accounts to be created with trivially weak passwords. - Reusing the same generated password across multiple database accounts or environments (dev, staging, production) โ generate a unique password per account.
Frequently Asked Questions
RAND() is seeded from the system clock by default and is statistically weak โ it was never designed to be unpredictable to an adversary. Wrapping it in MD5() doesn't fix this; it only hides the weak underlying value.
Outside the database โ in your application code, a deployment script, or a browser-based generator โ using a proper cryptographically secure random source. Then apply it with a standard ALTER USER or CREATE USER statement using bound parameters.
No, not unless the optional validate_password component is installed and configured, as shown above. Enabling it with a strong policy is recommended for any production database.
Need a password right now?
Generate one in your browser, then paste it into your ALTER USER statement.
Use the Password Generator โ