根本原因是 .env 中特殊字符未用双引号包裹导致 phpdotenv 静默截断,如 db_password=abc@123%test 应写为 db_password="abc@123%test";等号两侧不可有空格;database.php 中须写 'password' => env('db_password', '');需 utf-8 无 bom 编码、清缓存并验证。

ThinkPHP 6 使用 .env 配置数据库密码时,如果密码含 @、%、!、$、/、: 等特殊字符却连接失败,根本原因不是密码本身错误,而是 .env 文件被 vlucas/phpdotenv 解析时发生静默截断或解析失败。这会导致 env('DB_PASSWORD') 返回空、截短值或 null,最终 PDO 连接时用户名/密码为空或不完整,报错如 Access denied for user 或 SQLSTATE[HY000] [1045]。
.env 中特殊字符必须用双引号包裹
ThinkPHP 6 默认使用较新版本的 phpdotenv(v5.4+),它会对未加引号的值中出现的 @、$、% 等字符做变量展开或分隔处理,而非原样读取。
例如:
- ❌
DB_PASSWORD=abc@123%test→ 实际可能只读到abc或abc@123,%test被丢弃; - ✅
DB_PASSWORD="abc@123%test"→ 完整读取,无截断。
单引号在新版 dotenv 中虽可读字面量,但为兼容 CI/CD 工具链和 Laravel 生态,统一推荐使用双引号。
等号两侧绝对不能有空格
.env 格式极其严格:
- ❌
DB_PASSWORD = "abc@123"→ 整行被跳过,env()返回null; - ✅
DB_PASSWORD="abc@123"→ 正确加载。
空格问题不会报错,而是静默失效,极易排查遗漏。
database.php 中必须显式调用 env() 并提供默认值
仅在 .env 写 DB_PASSWORD=xxx 没用,必须在 config/database.php 中这样写:
'password' => env('DB_PASSWORD', ''),
- 第二个参数
''不可省略:传null会导致 PDO 构造时把密码当作空字符串,引发认证失败; - 若此处仍写死
'password' => '123',会完全覆盖环境变量,.env修改无效。
验证是否真正生效的快捷方式
在任意控制器中加入:
dump(getenv('DB_PASSWORD'), env('DB_PASSWORD'));
- 两个都为空 →
.env文件未被加载(检查路径、入口文件是否调用Env::load()); -
getenv()有值但env()为空 → ThinkPHP 的 Env facade 未生效或配置缓存未更新; - 两者一致但值不全 →
.env格式错误(如缺引号、含不可见字符)。
其他常见干扰项
- 文件编码必须是 UTF-8 无 BOM:Windows 记事本默认带 BOM,会导致解析失败,建议用 VS Code 或 Notepad++ 另存为「UTF-8 无签名」;
-
开启编辑器“显示不可见字符”:排查全角空格、
^M(Windows 换行)、零宽字符; -
改完
.env后必须清缓存:执行php think clear:config或手动删除runtime/cache/下配置缓存文件; -
确认
.env在项目根目录:与app/、public/、config/同级,不在public/或config/下。
不复杂但容易忽略











