MySQL MD5()函数返回32位小写十六进制字符串,不可逆、无盐、不安全,仅适用于数据校验等低安全场景;输入NULL返回NULL,空字符串有确定哈希值,多字段拼接需防NULL和碰撞,存储字段须为VARCHAR(32)或BINARY(16)。

MySQL 的 MD5() 函数能直接返回字符串的 32 位小写十六进制哈希值,但它是纯字符串输出,不是二进制,也不加盐,不能用于现代密码存储。
直接调用 MD5() 得到标准十六进制结果
它只接受一个字符串参数,输入 NULL 就返回 NULL,其余一律转成 32 字符小写 hex 字符串:
-
SELECT MD5('hello');→'5d41402abc4b2a76b9719d911017c592' -
SELECT MD5('');→'d41d8cd98f00b204e9800998ecf8427e'(空字符串也有确定结果) - 字段参与计算时:
SELECT MD5(username) FROM users;,注意字段本身是NULL会导致对应行结果为NULL
别指望它大小写可变或自动 trim 空格——MD5('hello ') 和 MD5('hello') 完全不同,空格算在输入里。
WHERE 条件中比对 MD5 值必须严格一致
常见错误是把哈希值当二进制或带前缀处理,导致条件永远不成立:
- ❌ 错误写法:
WHERE password = UNHEX('5d41402abc4b2a76b9719d911017c592')—— 左边是 varchar,右边是 binary,类型不匹配,隐式转换后恒为 false - ✅ 正确写法:
WHERE password = '5d41402abc4b2a76b9719d911017c592'(假设password字段存的就是 hex 字符串) - 如果字段类型是
BINARY(16),那得先UNHEX(MD5('hello'))再存,查询时也得用UNHEX()包裹字面量
大小写敏感:MySQL 默认校对规则下,'ABC' ≠ 'abc',而 MD5() 永远输出小写,所以比对字段也必须是小写存储或显式 LOWER() 转换。
多字段拼接哈希时注意分隔与 NULL 处理
用 CONCAT() 组合多个字段再哈希,最容易踩 NULL 导致整个结果为 NULL:
- ❌
MD5(CONCAT(name, email))—— 若email是NULL,整个CONCAT返回NULL,哈希结果也是NULL - ✅ 改用
CONCAT_WS(':', name, email),自动跳过 NULL;或显式处理:MD5(CONCAT(IFNULL(name,''), ':', IFNULL(email,''))) - 务必加明确分隔符,否则
CONCAT('ab','c')和CONCAT('a','bc')结果相同,哈希碰撞风险陡增
字段长度要留足:32 字符 hex 值,VARCHAR(32) 刚好,VARCHAR(31) 会截断,存不全。
批量更新字段为 MD5 值要防锁表和长度溢出
直接 UPDATE table SET hash_col = MD5(id); 在大表上可能锁死业务:
- 分批执行更安全:
UPDATE table SET hash_col = MD5(id) WHERE id BETWEEN 1 AND 5000;,配合主键范围推进 - 确认目标字段类型支持 32 字符:
SHOW COLUMNS FROM table LIKE 'hash_col';,避免因VARCHAR(20)导致静默截断 - 更新后立刻验证:
SELECT id, hash_col, LENGTH(hash_col), MD5(id) FROM table WHERE id IN (1,2,3) AND hash_col != MD5(id);
MD5 本身无盐、不可逆、易碰撞,仅适合低安全场景如数据指纹或临时标识;生产环境密码请用 SHA2() + 随机 salt,或交由应用层 bcrypt/scrypt 处理。











