Why PHP Can't Talk to Your New MySQL 8
You spin up a fresh MySQL 8.0 server, create a user for your app, point your PHP code at it, and get this:
Warning: mysqli_connect(): The server requested authentication method unknown to the client [caching_sha2_password]
With PDO it shows up as SQLSTATE[HY000] [2054] The server requested authentication method unknown to the client. Your password is fine. PHP and MySQL simply don’t agree on how to check it.
What changed in MySQL 8.0
MySQL’s upgrade notes on caching_sha2_password explain it. As of 8.0, caching_sha2_password is the preferred and default authentication plugin instead of mysql_native_password, and the server’s default_authentication_plugin variable changed to match. MySQL says it gives more secure password hashing, and its docs describe an in-memory cache of successful logins that keeps repeat connections quick.
Two details matter. The new default only applies to accounts created after you install or upgrade to 8.0, so accounts that came across in an upgrade keep their old plugin. And the server tells every client its default plugin during the handshake, even when the account you’re logging into uses something else.
Why PHP chokes
PHP’s mysqli and pdo_mysql usually sit on mysqlnd, PHP’s own implementation of the MySQL protocol, and that’s where the two problems are.
The first bites older PHP. The PHP manual’s MySQL 8 note says PHP before 7.1.16, or PHP 7.2 before 7.2.4, fails with that error against a MySQL 8 server whose default is caching_sha2_password, even if your account doesn’t use it. Newer releases fall back gracefully when they see an unfamiliar default in the handshake.
The second bites everyone. mysqlnd in current PHP releases, 7.3 included, doesn’t implement caching_sha2_password at all, so any account using it fails with the same message. MySQL’s own compatibility list says the same thing right now: PDO_MySQL and mysqli don’t support it, while the separate mysql_xdevapi extension does. Support did show up briefly last year. PHP 7.1.20 through 7.1.22 and 7.2.8 through 7.2.10 shipped it, but it was reverted in September after a bug report showed it didn’t work correctly in some cases, and releases from 7.1.23 and 7.2.11 onward don’t have it. It was put back in November for PHP 7.4, which isn’t out yet.
So the honest answer today is that there’s no current PHP release you can upgrade to that fixes this properly. What you can do is get onto a PHP release that handles the handshake (7.1.16, 7.2.4, any 7.3) and give your app an account PHP understands.
The fix I’d use: one native password account
Create the app’s user with the old plugin explicitly, and leave everything else on the new default:
CREATE USER 'app'@'10.0.0.%' IDENTIFIED WITH mysql_native_password BY 'long-random-password';
GRANT SELECT, INSERT, UPDATE, DELETE ON shop.* TO 'app'@'10.0.0.%';
If the user already exists, ALTER USER 'app'@'10.0.0.%' IDENTIFIED WITH mysql_native_password BY '...' does the same thing. Your admin accounts and anything connecting with the mysql command line client (which is built on libmysqlclient and supports the new plugin in 8.0) keep caching_sha2_password.
The quick fix, and why I’d avoid it
The other option you’ll see everywhere is flipping the whole server back in my.cnf:
[mysqld]
default_authentication_plugin=mysql_native_password
That only helps accounts created after the change (an existing app user on caching_sha2_password still needs the ALTER USER above), and it changes the default for every account created from then on, including ones that have no reason to use the old plugin. MySQL’s docs say this setting should be viewed as temporary rather than a long term solution, because new accounts made with it lose the improved authentication security. It’s also easy to forget it’s there a year from now.
The security tradeoff
Either way, you’re trading away the stronger password hashing MySQL now recommends for the accounts that use the old plugin. I think that’s acceptable for a single, narrowly scoped app account, as long as you keep the rest of the basics tight. Use a long random password, limit the host the account can connect from, grant only what the app needs, and don’t let the database port face the internet. If traffic crosses a network you don’t control, turn on TLS between PHP and MySQL regardless of the plugin.
Then write yourself a reminder. Once you’re on a PHP release whose mysqlnd supports caching_sha2_password, move the account back with ALTER USER ... IDENTIFIED WITH caching_sha2_password BY '...'. Keep in mind that MySQL requires a secure connection (TLS, a Unix socket, shared memory, or RSA key pair based password exchange) the first time an account authenticates with that plugin after its cached entry is cleared (a restart, a password change, or a FLUSH PRIVILEGES all do it), so test that path before you flip it.