PHP创建数据库后需在MySQL层面创建只读用户并授予SELECT权限,禁止INSERT/UPDATE/DELETE等写权限,且权限须限定到具体库,如CREATE USER 'myapp_ro'@'localhost' IDENTIFIED BY 'pwd'; GRANT SELECT ON myapp_db.* TO 'myapp_ro'@'localhost'; FLUSH PRIVILEGES;。

PHP 创建数据库后如何分配只读用户
PHP 本身不直接管理 MySQL 用户权限,它只是通过数据库连接执行 SQL 命令。真正设只读权限,必须在 MySQL 层面创建用户并授予 SELECT 权限,且**不能授予 INSERT、UPDATE、DELETE、DROP、CREATE 等写操作权限**。
常见错误是:用 mysqli 或 PDO 连接 root 创建库后,误以为“只给这个用户连这个库”就等于只读——其实只要账号有写权限,连上去就能删表。
- 先用高权限账号(如 root)执行授权语句,不是在 PHP 里“设置”
- 推荐为每个业务库单独建只读用户,避免跨库越权
- 权限要明确限定到具体数据库,别用
ON *.*
MySQL 中创建只读用户的完整命令
假设你刚用 PHP 执行 CREATE DATABASE myapp_db,接下来需在 MySQL 中运行:
CREATE USER 'myapp_ro'@'localhost' IDENTIFIED BY 'strong_password_123'; GRANT SELECT ON `myapp_db`.* TO 'myapp_ro'@'localhost'; FLUSH PRIVILEGES;
关键点:
立即学习“PHP免费学习笔记(深入)”;
-
'myapp_ro'@'localhost'的主机部分要和 PHP 连接时的host一致(如 PHP 连的是127.0.0.1,这里就得写'myapp_ro'@'127.0.0.1') -
GRANT SELECT ON `myapp_db`.*中的反引号防止库名含特殊字符;.*表示该库下所有表 - 别漏掉
FLUSH PRIVILEGES,否则权限不生效 - 如果应用需要查
information_schema(比如 ORM 自动探测字段),可额外加GRANT SELECT ON information_schema.*,但非常规需求不建议
PHP 连接只读用户时的验证与容错
连上只读用户后,任何写操作都会报错,典型错误信息是:SQLSTATE[42000]: Syntax error or access violation: 1142 INSERT command denied to user。这不是 PHP 报错,而是 MySQL 返回的权限拒绝。
- 用
PDO时开启异常模式:new PDO($dsn, $user, $pass, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]),才能捕获这类错误 - 测试阶段可在代码里故意执行
INSERT INTO ... VALUES(...),确认是否真被拦截 - 某些框架(如 Laravel)的迁移命令或缓存初始化会尝试写表,切勿用只读账号跑
php artisan migrate或php artisan config:cache
为什么不能只靠 PHP 层控制读写?
因为 PHP 是应用层,权限控制在数据库服务端。哪怕你在 PHP 类里把 save() 方法空实现,只要数据库账号本身有写权限,攻击者绕过你的代码直连 MySQL 就能删库。
真正的只读,是让 MySQL 拒绝一切非 SELECT 请求。这也是生产环境最小权限原则的核心:账号能力 = 实际所需能力,不多一分。
容易忽略的是:视图(VIEW)、存储过程(PROCEDURE)也可能隐式执行写操作,所以只读用户也不该被授予 EXECUTE 权限,除非明确知道过程内只读。











