access denied核心原因是user@host组合不匹配或权限缺失:mysql将'localhost'、'127.0.0.1'、'%'视为独立账户,需严格匹配;必须授予对应create等具体权限并执行flush privileges;mysql 8+默认caching_sha2_password插件可能与旧版php不兼容。

Access denied 不是密码错了重试就行,而是 MySQL 拒绝了整个认证流程——核心卡点就两个:user@host 组合不匹配,或该组合没被授予对应权限。
查清楚你连的是哪个 user@host
PHP 里写的 'localhost' 和 MySQL 里存的 'root'@'localhost' 必须严丝合缝。MySQL 把 'localhost'、'127.0.0.1'、'%' 当成三个独立账户,哪怕用户名一样、密码一样,权限也互不相干。
登录 MySQL(用已有高权限账号),执行:
SELECT User, Host FROM mysql.user WHERE User = 'your_user';
看返回结果里有没有跟你 PHP 连接语句中完全一致的 Host 值。常见坑:
- PHP 写的是
'localhost',但 MySQL 里只建了'myapp'@'127.0.0.1'→ 必然报错 - PHP 写的是
'127.0.0.1',但 MySQL 里只有'myapp'@'localhost'→ 同样失败 - 想让应用从 Docker 容器连宿主机 MySQL,PHP 里填
'host.docker.internal'或'172.17.0.1',但 MySQL 用户没授权给这个Host→ 连不上
确认用户有 CREATE 权限(建库前必做)
能连上 ≠ 能建库。CREATE DATABASE 是独立权限,普通 SELECT 或 INSERT 权限完全不够。即使你用 root 连,如果它在 MySQL 8+ 里被限制了权限范围,也会失败。
检查当前用户的实际权限:
SHOW GRANTS FOR 'myapp'@'localhost';
输出里必须包含类似:
GRANT CREATE ON *.* TO 'myapp'@'localhost'
或至少:
将 WCAG 2 AA 无障碍标准应用于设计系统、UI 组件和网页——通过可运行的验证器进行对比度计算,采用设计 token 模式使颜色天生可访问,设定排版和焦点状态规则,并提供语义检查清单。适用于构建或审查 UI。
GRANT CREATE ON `mydb`.* TO 'myapp'@'localhost'
如果没有,补授权:
- 只允许建指定前缀的库:
GRANT CREATE ON `myapp_%`.* TO 'myapp'@'localhost'; - 允许建任意库(开发环境可选):
GRANT CREATE ON *.* TO 'myapp'@'localhost'; - 别忘了执行:
FLUSH PRIVILEGES;
MySQL 8+ 的 caching_sha2_password 插件兼容性
PHP 用 mysqli_connect() 或 PDO 连 MySQL 8.0+ 时,如果用户认证插件是 caching_sha2_password(MySQL 8 默认),而你的 PHP 没启用 mysqlnd 或版本太低,就会静默失败,报出看似“密码错误”的 Access denied。
查插件类型:
SELECT User, Host, plugin FROM mysql.user WHERE User = 'myapp';
如果插件是 caching_sha2_password,且你确认 PHP 版本较老(如 PHP 7.2 或未开启 mysqlnd),就换回兼容的插件:
ALTER USER 'myapp'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_pass';
再执行:FLUSH PRIVILEGES;
验证 PHP 是否支持:phpinfo() 页面搜 mysqlnd,必须看到已启用。
连接代码里最容易漏掉的细节
不是所有报错都来自配置,有些是代码写法触发了隐式失败:
- 用
mysqli_connect('localhost', 'u', 'p', 'db_name')—— 如果db_name还不存在,连接会直接失败,报 Access denied(不是权限问题,是库不存在导致初始化中断)→ 改成不带库名连接:mysqli_connect('localhost', 'u', 'p'),再单独query("CREATE DATABASE...") - 没检查连接返回值:
if (!$conn) { die(mysqli_connect_error()); }缺了这句,页面空白,你根本看不到真实错误 - 密码含特殊字符(如
@、/)被 URL 解析或 shell 截断 → 在 PHP 里用单引号包裹,或提前rawurldecode()
真正卡住的地方,往往不是“不知道怎么做”,而是 user@host 这个组合没对上、权限没显式赋予、或者插件不兼容却没意识到——三者缺一不可。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










