DATABASE_URL应按连接方式选IP:公网直连填公网IP,SSH隧道填127.0.0.1,同VPC填内网IP;禁用localhost防Unix socket错误;密码含特殊字符需URL编码;serverVersion必须显式指定主版本号;doctrine:database:create失败因用户缺CREATE权限。

DATABASE_URL 里写公网 IP 还是内网 IP?
取决于你用哪种方式连——直接远程连接就填云服务器的公网 IP,走 SSH 隧道就填 127.0.0.1(因为隧道把远程端口映射到了本地),应用和数据库同属一个云厂商 VPC 就必须填内网 IP。
别用 localhost:MySQL 在 Linux 下遇到 localhost 会强制走 Unix socket,而远程数据库根本没有这个文件,直接报 SQLSTATE[HY000] [2002] No such file or directory。
常见错误现象:
-
Connection refused:安全组没开数据库端口(3306 等),或数据库 bind-address 没监听 0.0.0.0 -
Access denied for user:用户权限只给了'user'@'localhost',没给'user'@'%'或具体云服务器 IP - 连得上但查不出数据:用户有连接权没 SELECT 权,GRANT 语句漏了库表范围
密码含 @ / : / / 怎么处理?
URL 中的 @、:、/ 是分隔符,如果密码里有它们,不编码就会被误解析。比如 DATABASE_URL="mysql://u:p@ss:w0rd@1.2.3.4:3306/db" 实际会被拆成用户 u、密码 p、主机 ss:w0rd@1.2.3.4——显然错了。
必须做 URL 编码:
-
@→%40 -
:→%3A -
/→%2F - 可用 PHP 的
urlencode()或在线工具快速转义
正确示例:DATABASE_URL="mysql://db_user:pass%40word%3A123@1.2.3.4:3306/myapp?serverVersion=8.0"
serverVersion 不写会怎样?
Doctrine 需要它来决定生成 SQL 的语法兼容性。不写会导致:
- MySQL 8.0+ 的窗口函数、CTE 报错或被降级为子查询
-
doctrine:schema:update可能误判字段类型差异(比如 JSON 类型在 5.7 和 8.0 行为不同) - 某些迁移命令执行失败,提示 “Unknown database version”
务必显式指定:
- MySQL 8.0.x →
serverVersion=8.0 - MySQL 5.7 →
serverVersion=5.7 - MariaDB 10.5 →
serverVersion=mariadb-10.5
注意:值不能写成 8.0.33 这种带补丁号的完整版本,Doctrine 只认主版本号。
为什么 doctrine:database:create 总是 Access denied?
这个命令不是用 root 登录建库,而是用 DATABASE_URL 里的用户去连——所以失败根本不是配置格式问题,是权限不足。
该用户至少需要:
-
CREATE权限(建库) -
GRANT OPTION(可选,方便后续赋权) - 若还要自动建表,得加
CREATE TEMPORARY TABLES和INDEX
执行这条 SQL 授权(替换 your_user 和 % 为实际值):
GRANT CREATE ON *.* TO 'your_user'@'%'; FLUSH PRIVILEGES;
如果云数据库管控严格(如阿里云 RDS),可能禁止 ON *.*,那就换用控制台手动建库,再运行 php bin/console doctrine:schema:create。
复杂点在于:很多云厂商默认关闭 super_priv,连 SET GLOBAL sql_mode 都不允许,这时候 doctrine:schema:update --force 很容易因 SQL mode 差异失败——优先走 migration 文件,别图省事。


















