MySQL 8.0 reached end of life in April 2026, which means no more security fixes from Oracle for the community edition. The supported target is MySQL 8.4, the current long-term support (LTS) release. The move is a direct in-place upgrade, but 8.4 removed a number of things that 8.0 still accepted. Most of them fail quietly until the day a user cannot log in or the server refuses to start. This guide lists what breaks, gives a query or command for finding each one in your own system, and walks through the upgrade.

The short version

  • You can upgrade directly from MySQL 8.0 to 8.4 (the manual's example path is 8.0.37 to 8.4.x). An in-place upgrade is supported. If you are still on 5.7, go to 8.0 first.
  • Run MySQL Shell's upgrade checker against the server before you do anything else.
  • The usual breakages are accounts that use mysql_native_password, removed settings in my.cnf, old replication commands in scripts, and changed InnoDB defaults.
  • There is no mysql_upgrade step. The 8.4 server upgrades the data dictionary and system tables itself when it starts.

Step 1: run the upgrade checker

MySQL's own checker finds many of the problems below automatically. It ships with MySQL Shell, so use the 8.4 version of the shell, because the checker can only target versions up to the shell's own release number:

mysqlsh -- util checkForServerUpgrade root@localhost:3306 \ --target-version=8.4.0 --output-format=JSON --config-path=/etc/mysql/my.cnf 

Pass --config-path, or the checks that read your configuration file will fail. The account needs the RELOAD, PROCESS and SELECT privileges. Relevant checks include removedSysVars, removedFunctions, pluginUsage and authMethodUsage. The sections below show how to look for the same things by hand, which is useful when you want to see exactly what is affected.

What breaks, and how to find it

1. Accounts that use mysql_native_password

In 8.4 the mysql_native_password plugin is still present but disabled by default. Release note wording: it "can be enabled by starting MySQL with the new --mysql-native-password=ON server option, or by adding mysql_native_password=ON to the [mysqld] section". Any account that still uses it cannot log in until you change the account or turn the plugin back on. Find them:

SELECT user, host, plugin FROM mysql.user WHERE plugin = 'mysql_native_password'; 

On my test server, an account created with IDENTIFIED WITH mysql_native_password appeared here, and the system accounts did not. Fix each one before the upgrade by moving it to the default plugin. You must supply the password again, because the stored hash cannot be converted:

ALTER USER 'app'@'%' IDENTIFIED WITH caching_sha2_password BY 'the-password'; 

I ran this on MySQL 8.0.46 and then connected from PHP 8.3 (PDO MySQL) with the same credentials, and the connection worked. A PHP app or Laravel's mysql connection needs no other change for this. If you cannot change an account yet, such as one used by an old client library, add mysql_native_password=ON under [mysqld] as a temporary measure and plan to remove it, because the plugin is deprecated.

2. Settings in my.cnf that no longer exist

Removed options cause an error at startup rather than being ignored. Search your config and any systemd or Docker arguments for these:

grep -rniE 'default[-_]authentication[-_]plugin|expire[-_]logs[-_]days|skip[-_]ssl|^ *ssl *=|have_ssl|skip[-_]host[-_]cache|innodb *=|master[-_]info|relay[-_]log[-_]info|transaction[-_]write[-_]set' /etc/mysql /etc/my.cnf* 2>/dev/null 
Removed Use instead
default_authentication_plugin authentication_policy
expire_logs_days binlog_expire_logs_seconds
--ssl, --skip-ssl, --admin-ssl, have_ssl, have_openssl --tls-version, --admin-tls-version
--skip-host-cache --host-cache-size=0
--innodb, --skip-innodb Nothing; InnoDB is always on
--master-info-repository, --relay-log-info-repository, --master-info-file, --relay-log-info-file, transaction_write_set_extraction Remove them

This is not the full list; the release notes for 8.4.0 have the rest. The expire_logs_days removal date is worded inconsistently in the manual, but the 8.4 manual states it is removed and gives binlog_expire_logs_seconds as the replacement.

3. Old replication commands in scripts and monitoring

The "master/slave" statements are gone in 8.4. Anything that runs them, such as failover scripts, cron jobs, backup tooling and monitoring queries, fails with a syntax error:

Removed in 8.4 Replacement
START SLAVE / STOP SLAVE START REPLICA / STOP REPLICA
SHOW SLAVE STATUS SHOW REPLICA STATUS
SHOW SLAVE HOSTS SHOW REPLICAS
RESET SLAVE RESET REPLICA
CHANGE MASTER TO ... MASTER_HOST ... CHANGE REPLICATION SOURCE TO ... SOURCE_HOST ...
SHOW MASTER STATUS SHOW BINARY LOG STATUS
RESET MASTER RESET BINARY LOG AND GTIDS
PURGE MASTER LOGS, SHOW MASTER LOGS PURGE BINARY LOGS, SHOW BINARY LOGS

The options inside these statements are renamed as well, so MASTER_USER becomes SOURCE_USER and MASTER_LOG_FILE becomes SOURCE_LOG_FILE. The status counters Com_show_slave_status and Com_change_master are also removed (replaced by Com_show_replica_status and Com_change_replication_source), which matters if a dashboard reads them. Search your tooling:

grep -rniE 'start slave|stop slave|show slave|reset slave|change master|show master|reset master|purge master|master_(host|user|password|log_file|log_pos|auto_position)' /opt /usr/local/bin /etc/cron* 2>/dev/null 

4. FLOAT or DOUBLE columns with AUTO_INCREMENT

8.4 no longer allows AUTO_INCREMENT on FLOAT or DOUBLE columns. The release notes say the upgrade requires altering such tables first. Find them:

SELECT table_schema, table_name, column_name, data_type FROM information_schema.columns WHERE extra LIKE '%auto_increment%' AND data_type IN ('float', 'double'); 

On my test server this returned the one table I had created with id FLOAT AUTO_INCREMENT. Change those columns to an integer type before upgrading.

5. Foreign keys that point at non-unique columns

A foreign key that references a non-unique or partial key is nonstandard. In 8.4 the new setting restrict_fk_on_non_standard_key is ON by default, so creating one is rejected. The manual says upgrades from 8.0 are still supported when such keys exist, and the server logs warnings naming them. The practical risk is later: a CREATE TABLE or ALTER TABLE in your migrations that adds this kind of key will fail. Find existing ones with this query, which compares each foreign key's referenced columns with the unique indexes on the parent table:

WITH fk AS ( SELECT CONSTRAINT_SCHEMA AS fk_schema, TABLE_NAME AS fk_table, CONSTRAINT_NAME AS fk_name, REFERENCED_TABLE_SCHEMA AS ref_schema, REFERENCED_TABLE_NAME AS ref_table, GROUP_CONCAT(REFERENCED_COLUMN_NAME ORDER BY ORDINAL_POSITION) AS ref_cols FROM information_schema.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_NAME IS NOT NULL GROUP BY CONSTRAINT_SCHEMA, TABLE_NAME, CONSTRAINT_NAME, REFERENCED_TABLE_SCHEMA, REFERENCED_TABLE_NAME ), uq AS ( SELECT TABLE_SCHEMA AS t_schema, TABLE_NAME AS t_table, GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) AS cols FROM information_schema.STATISTICS WHERE NON_UNIQUE = 0 GROUP BY TABLE_SCHEMA, TABLE_NAME, INDEX_NAME ) SELECT fk.fk_schema, fk.fk_table, fk.fk_name, fk.ref_table, fk.ref_cols FROM fk LEFT JOIN uq ON uq.t_schema = fk.ref_schema AND uq.t_table = fk.ref_table AND uq.cols = fk.ref_cols WHERE uq.cols IS NULL; 

On my test server it flagged a foreign key pointing at a non-unique index and another pointing at only the first column of a two-column unique index. A foreign key to a primary key, and one to the full two-column unique index, were not flagged. Fix flagged keys by pointing them at a unique key, or set restrict_fk_on_non_standard_key=OFF if you must keep them.

6. Changed InnoDB defaults

If you never set these in my.cnf, 8.4 behaves differently from 8.0 without any error. These come from the 8.4 manual's table of differing defaults. The "8.0 value" column is what I read from a running MySQL 8.0.46 server, and it matched the manual:

Variable 8.0 default 8.4 default
innodb_adaptive_hash_index ON OFF
innodb_change_buffering all none
innodb_flush_method (Linux) fsync O_DIRECT if supported, otherwise fsync
innodb_io_capacity 200 10000
innodb_log_buffer_size 16 MiB 64 MiB
innodb_purge_threads 4 1 if 16 or fewer logical CPUs, otherwise 4
temptable_max_ram 1 GiB 3% of RAM, within 1 to 4 GiB
temptable_max_mmap 1 GiB 0 (off)

The manual lists more (for example innodb_buffer_pool_instances, innodb_doublewrite_files and innodb_page_cleaners). Before upgrading, record what your server runs today, then compare after:

SELECT @@innodb_adaptive_hash_index, @@innodb_change_buffering, @@innodb_flush_method, @@innodb_io_capacity, @@innodb_log_buffer_size, @@innodb_purge_threads, @@temptable_max_ram, @@temptable_max_mmap; 

If a workload depended on the old behaviour, such as the adaptive hash index for read-heavy lookups, set the value explicitly in my.cnf rather than relying on a default. Measure with your own workload instead of assuming either direction is faster.

7. Other removals worth a search

  • mysql_upgrade is removed. Scripts or Ansible roles that call it will fail. The server does that work at startup.
  • mysqlpump is removed, along with lz4_decompress and zlib_decompress. Use mysqldump or MySQL Shell's dump utilities.
  • FLUSH HOSTS is removed. Use TRUNCATE TABLE performance_schema.host_cache or mysqladmin flush-hosts.
  • LOCK TABLES ... LOW_PRIORITY WRITE is now a syntax error.
  • TheSET_USER_IDprivilege is removed. Grants that mention it fail; use SET_ANY_DEFINER and ALLOW_NONEXISTENT_DEFINER.
  • Keyring and FIDO plugins such as keyring_file, keyring_encrypted_file, keyring_oci and authentication_fido are removed in favour of the component_keyring_* components and authentication_webauthn. If you use encrypted tablespaces, read the keyring notes before upgrading.
  • Weak TLS ciphers are no longer supported in ssl_cipher and related settings.

Step 2: the in-place upgrade

The manual's procedure for package or binary installs, with my additions marked:

  1. Back up first (my addition; the manual's in-place steps do not include it). Take a logical dump or a physical backup and confirm you can restore it.
  2. If you use InnoDB XA transactions, run XA RECOVER; and commit or roll back anything it lists.
  3. If you normally run with innodb_fast_shutdown=2, switch to a fast or slow shutdown:SET GLOBAL innodb_fast_shutdown = 0; -- slow shutdown (1 = fast)
  4. Shut the server down cleanly: mysqladmin -u root -p shutdown.
  5. Install the 8.4 packages or binaries.
  6. Start MySQL 8.4 on the existing data directory. If you have encrypted InnoDB tablespaces, load the keyring with --early-plugin-load.

On first start the server upgrades the data dictionary, the mysql system database, and the Performance Schema, INFORMATION_SCHEMA and sys schemas. The manual says that if the dictionary step fails, the server reverts its changes, and you should start the old server again, fix the cause and retry. Read the error log during the first start (my addition), and do not put the service back into rotation until it has finished.

After the upgrade

  • Confirm the version: SELECT VERSION();
  • Re-run your account query and a connection from each application, including read replicas, cron jobs and reporting tools.
  • Check replication with SHOW REPLICA STATUS, using the new statement name.
  • Compare the variables you recorded earlier.
  • Time zone tables are not upgraded by the process. If you load them with mysql_tzinfo_to_sql, reload them as described in the time zone section of the manual.

Rollback

Plan to roll back by restoring your backup. The manual has a separate "Downgrading MySQL" section, which I did not review, so read it before relying on any downgrade path. Test the whole procedure on a copy of production data first, with the same config file.

Frequently asked questions

Can I upgrade from MySQL 8.0 directly to 8.4?

Yes. The manual lists "8.0.37 to 8.4.x LTS" as a supported path, with in-place upgrade, logical dump and load, or replication. From 5.7 you must go through 8.0 first.

Do I still need to run mysql_upgrade?

No. The utility was removed in 8.4.0. The server upgrades the data dictionary and system tables when it starts.

Will my Laravel or PHP app work with MySQL 8.4?

Generally yes, as long as the database user does not use mysql_native_password. I connected from PHP 8.3 with PDO MySQL to a caching_sha2_password account on 8.0 successfully. Check your migrations too, since a foreign key to a non-unique column will now be rejected.

Is MySQL 8.0 still safe to run?

Not for new deployments. It reached end of life in April 2026, so new vulnerabilities will not be patched in the community edition.

What about managed services like RDS or Aurora?

Their upgrade process and support dates are set by the provider. The incompatibilities in this article still apply to your accounts, configuration and SQL, so follow the provider's upgrade documentation as well.

Sources

Originally published on DEV Talk.