Laravel通过在config/database.php中为同一mysql连接配置read和write子数组实现读写分离,框架自动将SELECT路由至读库、INSERT/UPDATE/DELETE等操作发往写库;需手动创建权限不同的MySQL用户并正确嵌套配置,不可拆分为两个独立connection。
phpMyAdmin里没法直接配“读用户/写用户”
mysql 本身没有 read-only user 或 write-only user 这种角色概念,phpmyadmin 只是图形界面,它不提供权限粒度到“只允许 select”或“禁止 select”的开关。所谓“独立读写用户”,本质是手动 grant 不同权限集的两个普通 mysql 用户,然后在 laravel 的 config/database.php 里分别指向它们。
必须手动执行 GRANT 语句,不能只靠 phpMyAdmin 点选
phpMyAdmin 的权限编辑页默认隐藏 EVENT、TRIGGER、LOCK TABLES 等关键权限项,勾选“所有权限”也不等于 GRANT ALL PRIVILEGES。Laravel 迁移、DB::statement()、模型事件等都可能触发这些权限,漏掉就会报错。
- 读用户(如
laravel_reader)至少需要:SELECT、SHOW VIEW、USAGE - 写用户(如
laravel_writer)必须额外加:INSERT、UPDATE、DELETE、CREATE、DROP、ALTER、INDEX、REFERENCES、TRIGGER、EVENT - 无论读写用户,host 必须匹配 Laravel 服务器 IP(比如
'laravel_reader'@'10.0.2.10'),不能用%除非你清楚风险 - 执行完
GRANT后,一定要运行FLUSH PRIVILEGES;,否则权限不生效
Laravel 配置里不能写两个独立 connection
常见错误是建了 mysql_read 和 mysql_write 两个 connection,然后在代码里手动切——这不算读写分离,事务、连接复用、sticky 都失效。Laravel 要求把读写用户信息塞进同一个 connection 的 read / write 子键里。
-
read必须是数组,哪怕只有一个从库也要写成[['host' => '...', 'username' => 'laravel_reader', 'password' => '...']] -
write必须是关联数组,且只能一个元素:['host' => '...', 'username' => 'laravel_writer', 'password' => '...'] - 共用配置(
database、charset、collation等)必须写在外层,不能重复塞进read/write里 -
sticky => true要显式开启,否则刚save()就find()会查不到数据
读用户密码泄露风险比写用户更隐蔽
读用户权限低,容易被当成“安全账户”随意暴露在日志、监控或调试输出里。但只要拿到 host + username + password,攻击者就能全量导出数据库。Laravel 的 DB::select('SHOW PROCESSLIST')、DB::table('users')->get() 这类操作全走读连接,一旦读用户被扫出,相当于裸奔。
真正难处理的是主从延迟和 sticky 生效边界:一次请求里先 User::create() 再 User::find() 走主库没问题,但如果中间穿插了 DB::connection('mysql')->table('logs')->insert(...),这个 insert 是写操作,会触发 sticky,后续所有 Model::all() 都强制走主库——这点很容易被忽略,导致你以为“读流量没打到从库”,其实是 sticky 在起作用。
立即学习“PHP免费学习笔记(深入)”;



















