Laravel: Access denied for user 'forge'@'localhost' (but no such user is used in the app)

Viewed 9047

I've a Laravel application that works well but for some strange reason there is a lot of strange messages in log files:

[2019-10-04 10:24:21] production.ERROR: SQLSTATE[HY000] [1045] Access denied for user 'forge'@'localhost' (using password: NO) {"exception":"[object] (Doctrine\DBAL\Driver\PDOException(code: 1045): SQLSTATE[HY000] [1045] Access d enied for user 'forge'@'localhost' (using password: NO) at /var/www/html/pzw_prod/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:31, PDOException(code: 1045): SQLSTATE[HY000] [1045] Access denied for user 'forge'@'l ocalhost' (using password: NO) at /var/www/html/pzw_prod/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:27)

The thing is, I'm not connecting to database with user named forge. My .env uses completely different logins. And, I repeat, everything works fine: communication with database works as expected. Data is being successfully read and written.

So... why this message in log files?

UPDATE:

config('database')

$ php artisan tinker
Psy Shell v0.9.9 (PHP 7.2.22 — cli) by Justin Hileman
>>> config('database')
=> [
     "default" => "mysql",
     "connections" => [
       "sqlite" => [
         "driver" => "sqlite",
         "url" => null,
         "database" => /* CENSORED */,
         "prefix" => "",
         "foreign_key_constraints" => true,
       ],
       "mysql" => [
         "driver" => "mysql",
         "url" => null,
         "host" => "127.0.0.1",
         "port" => "3306",
         "database" => /* CENSORED */,
         "username" => "prod_pzw",
         "password" => /* CENSORED */,
         "unix_socket" => "",
         "charset" => "utf8",
         "collation" => "utf8_unicode_ci",
         "prefix" => "",
         "prefix_indexes" => true,
         "strict" => true,
         "engine" => null,
         "options" => [],
       ],
       "pgsql" => [
         "driver" => "pgsql",
         "url" => null,
         "host" => "127.0.0.1",
         "port" => "3306",
         "database" => /* CENSORED */,
         "username" => "prod_pzw",
         "password" => /* CENSORED */,
         "charset" => "utf8",
         "prefix" => "",
         "prefix_indexes" => true,
         "schema" => "public",
         "sslmode" => "prefer",
       ],
       "sqlsrv" => [
         "driver" => "sqlsrv",
         "url" => null,
         "host" => "127.0.0.1",
         "port" => "3306",
         "database" => /* CENSORED */,
         "username" => "prod_pzw",
         "password" => /* CENSORED */,
         "charset" => "utf8",
         "prefix" => "",
         "prefix_indexes" => true,
       ],
     ],
     "migrations" => "migrations",
     "redis" => [
       "client" => "predis",
       "options" => [
         "cluster" => "predis",
         "prefix" => /* CENSORED */,
       ],
       "default" => [
         "url" => null,
         "host" => "127.0.0.1",
         "password" => null,
         "port" => "6379",
         "database" => 0,
       ],
       "cache" => [
         "url" => null,
         "host" => "127.0.0.1",
         "password" => null,
         "port" => "6379",
         "database" => 1,
       ],
     ],
   ]

UPDATE 2:

It seems that 'forge' is some kind of default login. It seems that sometimes Laravel is not using values from .env. How can I debug this?

$ cat config/database.php | grep -B 5 forge
        'mysql' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
--
        'pgsql' => [
            'driver' => 'pgsql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '5432'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
--
        'sqlsrv' => [
            'driver' => 'sqlsrv',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', 'localhost'),
            'port' => env('DB_PORT', '1433'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
2 Answers

I had this exact same problem for the past few days and I think I solved it:

The settings in .env are not always used for some reason or other and occasionally Laravel will just use the default settings in config/app.php and config/database.php.

config/app.php:

// Change the 'SomeRandomString' to the generated key from your .env
'key' => env('APP_KEY', 'SomeRandomString'),
 
'cipher' => 'AES-256-CBC',

config/database.php

'mysql' => [
    'driver'    => 'mysql',
    'host'      => env('DB_HOST', 'localhost'),
    'database'  => env('DB_DATABASE', 'forge'),
    'username'  => env('DB_USERNAME', 'forge'),
    'password'  => env('DB_PASSWORD', ''),
    'charset'   => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix'    => '',
    'strict'    => false,
],

Change localhost, database, username, password to your actual settings from the .env.

This example is for MySQL if you use another database engine, change to those variables instead.

There might be a better solution (more secure?) but this is what so far kept the error from showing up.

In a multithreaded webserver two instances of PHP will share the same environment variables. That's a problem, because process A may shut down and set its ENV variables to null while process B is running, then when process B is asking for a ENV variable it will return null, that's why env('DB_DATABASE', 'forge') will sometimes result in forge, and other times the correct ENV.

More info here, here and here

One solution is to stop running a threaded web server (even if you compile with thread safety PHP might run functions that are not thread safe.)

But a quick and simple fix to your issue is by running:

php artisan config:cache

That will cache your ENV and config which avoids the issue (laravel will not be calling getenv/putenv when configs are cached). The downside is you have to run this command anytime you make a change in your environment variables or configs.

Another solution I found is to place this line in your bootstrap/app.php file:

\Illuminate\Support\Env::disablePutenv();
Related