md5函数返回32位小写十六进制字符串,非二进制值,不适用于密钥派生或密码存储;仅适合数据完整性校验等有限场景,且需注意索引失效、字符集影响及空字符串与null的区别。

MD5函数返回的是16进制字符串,不是二进制哈希值
MySQL 的 MD5() 函数输出是 32 位小写十六进制字符串(如 "5d41402abc4b2a76b9719d911017c592"),不是原始字节。这意味着它不能直接用于需要二进制摘要的场景(比如和 OpenSSL 的 md5 -binary 结果比对),也不适合做密钥派生。
常见错误现象:SELECT MD5('hello') = UNHEX('5d41402abc4b2a76b9719d911017c592') 返回 0 —— 因为左边是字符串,右边是二进制,类型不匹配导致隐式转换失败。
- 如果真要存二进制形式,用
UNHEX(MD5('hello')),但字段类型得是BINARY(16)或VARBINARY(16) -
MD5()是确定性函数:相同输入永远得相同输出,毫无盐值(salt)可言,完全不防彩虹表 - MySQL 8.0+ 已明确标记
MD5()为“不安全哈希”,审计或合规场景下会被拦截
别用MD5做密码存储,连SHA2都比它强一点
用 MD5() 存用户密码等于把钥匙挂在门把手上。它计算太快、无盐、已被大规模破解。哪怕加个固定字符串拼接(MD5(CONCAT('salt', password))),也只是拖延时间,不解决根本问题。
使用场景限制很窄:仅限校验数据完整性(比如确认配置文本没被篡改)、临时 token 签名(非敏感)、或兼容旧系统迁移过渡。
- 生产环境密码必须用
SHA2(password, 256)或更优方案(如应用层用 bcrypt / Argon2) -
SHA2()返回的是 64 位十六进制字符串(SHA-256),同样需注意是否要转UNHEX() - MySQL 5.7+ 支持
VALIDATE_PASSWORD插件,启用后MD5()可能被禁止用于CREATE USER ... IDENTIFIED WITH mysql_native_password
MD5在WHERE条件里用会拖慢查询,尤其没索引时
对字段用 MD5(col) 做 WHERE 条件(比如 WHERE MD5(email) = 'xxx'),MySQL 无法走索引,只能全表扫描——因为函数改变了原始值,索引失效。
性能影响明显:100 万行表,没索引时可能从毫秒级变秒级;若该列本身有索引,但你写成 MD5(email),索引彻底作废。
- 正确做法是:提前算好 MD5 值,存在单独列(如
email_md5 CHAR(32)),并给它建索引 - 或者用生成列(MySQL 5.7+):
email_md5 VARCHAR(32) STORED AS (MD5(email)),再加索引 - 避免在 JOIN 条件里用
MD5(),两边都算一遍,CPU 白耗
不同MySQL版本对空值和NULL的处理一致,但别依赖它做逻辑分支
MD5(NULL) 永远返回 NULL,各版本行为稳定。但有人误以为 MD5('') 也返回 NULL,其实它返回 "d41d8cd98f00b204e9800998ecf8427e"(空字符串的 MD5)。
容易踩的坑在于:用 IFNULL(MD5(col), 'default') 本意是兜底,结果发现 col = '' 时还是进了 default 分支,因为没意识到空字符串 ≠ NULL。
- 检查是否为空应分开判断:
IF(col IS NULL OR col = '', 'default', MD5(col)) - 字符集影响结果:如果
col是 utf8mb4,而连接用 latin1,MD5()输入实际是乱码字节,结果不可控 - 所有参数都会被强制转为字符串再哈希,
MD5(123)和MD5('123')结果一样,但MD5(NOW())每次执行都不同











