RE:NODE

Databases11 min read

MySQL 8.4 LTS: what changed from 8.0 and what breaks

What MySQL 8.4 LTS changes for an app moving from 8.0: the LTS model, mysql_native_password off by default, new InnoDB defaults and removed options.

0 readers

MySQL 8.4 is the first long-term support release under Oracle's new release model, and since MySQL 8.0 reached end of life in April 2026 it is the version to be on. For most applications the upgrade from 8.0 is uneventful: the SQL is the same, the drivers are the same, the data files upgrade in place. What breaks is at the edges. Accounts using mysql_native_password cannot log in until the plugin is switched back on, because 8.4 disables it by default. Scripts using CHANGE MASTER TO, SHOW SLAVE STATUS, FLUSH HOSTS, mysqlpump or expire_logs_days fail, because they were removed. And a handful of InnoDB defaults changed - mostly for the better on fast storage, with one that small servers should override.

This guide covers the release model first, because it changes how you plan upgrades, then every change likely to affect an application or an administrator, then how to check a database before moving it.

LTS and Innovation releases#

Until 8.0, MySQL shipped one series for years and added features in patch releases: 8.0.x gained EXPLAIN ANALYZE at 8.0.18, hash joins at 8.0.18, innodb_redo_log_capacity at 8.0.30. That made "8.0" a moving target - two servers both called MySQL 8.0 could behave differently.

From 8.1 onwards, Oracle split releases into two tracks:

TrackVersionsCadenceSupportChanges within the series
Innovation8.1, 8.2, 8.3, 9.0, 9.1 and onAbout quarterlyUntil the next Innovation releaseNew features, removals, behaviour changes
LTS8.4, then a later 9.xAbout every two yearsAround eight years in totalBug and security fixes only

An LTS series is meant to be boring. 8.4.1, 8.4.2 and so on contain fixes, not new features or changed defaults, so a patch update should not change how your application behaves. Oracle lists 8.4 as supported until 2032, with premier support for the first five years of that. Innovation releases are for people who want new features early and are prepared to upgrade every few months; for a production application database, LTS is the sensible default.

The practical consequence is that features introduced in 8.1 to 8.3 arrive in 8.4 all at once, and so do the removals that the Innovation releases made along the way. That is why 8.0 to 8.4 has more breaking changes than a version number of 0.4 suggests.

Authentication: mysql_native_password is off#

This is the change that stops applications connecting.

mysql_native_password, the SHA-1-based plugin that was the default until 8.0, was deprecated in 8.0. In 8.4 it is still present but disabled by default. An account created with it exists, but logins fail until the server starts with:

my.cnf
[mysqld]mysql_native_password=ON

The same switch is available on the command line as --mysql-native-password=ON. It is a start-up option, not something an application user can change, and in MySQL 9.0 the plugin is removed entirely, so turning it back on buys time rather than solving anything. The real fix is to move accounts to caching_sha2_password, the default since 8.0:

sql
-- Find accounts still on the old pluginSELECT user, host, plugin FROM mysql.userWHERE plugin = 'mysql_native_password';-- Move one; the password must be set again because the hash format differsALTER USER 'app'@'%' IDENTIFIED WITH caching_sha2_password BY 'the-password';

Before doing that, check that the application's driver supports caching_sha2_password. Anything released in the last several years does: PHP's mysqlnd, Node's mysql2, PyMySQL, mysqlclient, Connector/J 8 and later, MySqlConnector for .NET. The original Node mysql package does not, nor do MySQL 5.7-era command-line clients. A client that cannot do it fails with Authentication plugin 'caching_sha2_password' cannot be loaded; one that can, but connects without TLS, needs the server's RSA public key or a TLS connection on first login - MySQL remote connections explains that behaviour.

Two smaller authentication changes: the default_authentication_plugin variable was removed (its job is done by authentication_policy, which also governs multi-factor authentication), and the authentication_fido plugins were removed in favour of authentication_webauthn.

Removed statements, options and tools#

Anything here that appears in a script, a configuration file or an ORM's admin tooling fails on 8.4. Most were deprecated during 8.0 with warnings.

RemovedUse instead
CHANGE MASTER TO, MASTER_* optionsCHANGE REPLICATION SOURCE TO, SOURCE_* options
START SLAVE, STOP SLAVE, RESET SLAVESTART REPLICA, STOP REPLICA, RESET REPLICA
SHOW SLAVE STATUS, SHOW SLAVE HOSTSSHOW REPLICA STATUS, SHOW REPLICAS
SHOW MASTER STATUS, SHOW MASTER LOGSSHOW BINARY LOG STATUS, SHOW BINARY LOGS
RESET MASTER, PURGE MASTER LOGSRESET BINARY LOGS AND GTIDS, PURGE BINARY LOGS
FLUSH HOSTSTRUNCATE TABLE performance_schema.host_cache
expire_logs_daysbinlog_expire_logs_seconds
default_authentication_pluginauthentication_policy
--ssl, --admin-ssl, have_ssl, have_openssl--tls-version, --admin-tls-version
--skip-host-cache--host-cache-size=0
mysqlpumpmysqldump or MySQL Shell dump utilities
mysql_upgradeNothing; the server upgrades itself at start-up
mysql_ssl_rsa_setupNothing; the server generates certificates itself
binlog_transaction_dependency_trackingNothing; writeset tracking is always used
AUTO_INCREMENT on FLOAT/DOUBLE columnsAn integer column

The replication syntax change catches monitoring scripts more than replication setups. A health check that runs SHOW SLAVE STATUS every minute and greps for Seconds_Behind_Master now gets a syntax error, and in SHOW REPLICA STATUS the column is Seconds_Behind_Source. Status variables like Com_show_slave_status were removed with them.

FLUSH HOSTS matters to anyone who has met Host is blocked because of many connection errors. The TRUNCATE replacement needs the DROP privilege on that table, which root has; mysqladmin flush-hosts still works and uses it internally.

Also removed: the --old and --new options, --language, avoid_temporal_upgrade and show_old_temporals, LOW_PRIORITY with LOCK TABLES ... WRITE, the keyring_file and keyring_encrypted_file plugins (replaced by components), INFORMATION_SCHEMA.TABLESPACES, and support for weak TLS ciphers - 8.4 accepts only ciphers with forward secrecy and authenticated encryption on TLS 1.2 and 1.3.

New InnoDB and server defaults#

8.4 changed a set of InnoDB defaults to suit modern hardware - NVMe storage and many cores - rather than the spinning disks the old ones were written for. Unless you set these explicitly, your server behaves differently after upgrading.

Variable8.08.4
innodb_io_capacity20010000
innodb_io_capacity_maxat least 2000twice innodb_io_capacity
innodb_log_buffer_size16M64M
innodb_flush_method (Linux)fsyncO_DIRECT where supported
innodb_use_fdatasyncOFFON
innodb_adaptive_hash_indexONOFF
innodb_change_bufferingallnone
innodb_buffer_pool_instances8 (1 if under 1 GB)Calculated; 1 if 1 GB or less
innodb_doublewrite_pagesinnodb_write_io_threads (4)128
innodb_read_io_threads4Half the logical CPUs, at least 4
innodb_purge_threads41 up to 16 logical CPUs, else 4
innodb_numa_interleaveOFFON
temptable_max_ram1G3% of memory, between 1 and 4 GB
temptable_use_mmap / temptable_max_mmapON / 1GOFF / 0

Most of these are improvements you get for free. O_DIRECT stops InnoDB double-caching pages in the operating system's cache. The higher I/O capacity lets background flushing keep up with fast storage. Turning off the adaptive hash index and change buffering removes two features that often caused contention and rarely paid off on modern workloads; if a specific read-heavy workload benefited, they can be turned back on.

The one to watch on a small server is temptable_max_ram. Its 8.4 default is never below 1 GB, which on a 1 or 2 GB server allows in-memory temporary tables to claim half the machine or all of it. Cap it - InnoDB tuning for small servers has numbers by plan size. innodb_dedicated_server, if you use it, no longer sets innodb_flush_method, and sizes the redo log from CPU count rather than memory.

Schema and privilege changes#

Foreign keys must reference unique keys. restrict_fk_on_non_standard_key defaults to ON, so creating a foreign key that references a non-unique index or only part of a key fails with ER_WARN_DEPRECATED_NON_STANDARD_KEY. Existing foreign keys of that kind survive the upgrade with warnings; new ones need the referenced columns to be a primary key or unique index, or the variable turned off.

Wildcards in database grants are deprecated. GRANT ... ON a database name containing % or _ still works as a pattern, but those characters are expected to become literals in a future release. Grant per database.

New privileges. FLUSH_PRIVILEGES (just for FLUSH PRIVILEGES; holders of RELOAD get it on upgrade), OPTIMIZE_LOCAL_TABLE, TRANSACTION_GTID_TAG, and SET_ANY_DEFINER with ALLOW_NONEXISTENT_DEFINER, which replace SET_USER_ID for creating objects with someone else as definer. That last change affects restores: a dump whose views and routines name a definer other than you needs SET_ANY_DEFINER to load as written. MySQL users and privileges covers definers in more detail.

Identifiers with more than one `$`. An unquoted identifier containing two or more dollar signs is a syntax error since 8.1. Rare, but it breaks loudly when it happens.

On the positive side, 8.4 brings the Innovation-era features with it: histograms that can be set to update automatically with ANALYZE TABLE, GTID tags for grouping transactions, and a mysql client that can disable its system shell escape with --system-command=OFF.

Checking a database before you upgrade#

MySQL Shell's upgrade checker inspects a running 8.0 server and reports everything that will be a problem on the target version: removed options in use, accounts on deprecated plugins, foreign keys on non-unique keys, reserved words used as identifiers, and more.

bash
$ mysqlsh root@old-server:3306 -- util check-for-server-upgrade --target-version=8.4.6

Run it with an account that can read the configuration and the mysql schema, read every error and warning, and fix what it reports on the old server first. The upgrade paths it supports:

FromTo 8.4How
8.0 (recent patch)YesIn place, or dump and load
8.1-8.3 InnovationYesIn place
5.7Not directlyUpgrade to 8.0 first, or dump and load
8.4.x8.4.yIn place; downgrades within the 8.4 series are supported too

In-place means stopping the old server and starting the new binaries on the same data directory; the server upgrades its data dictionary and system tables itself at first start. On a hosted database, where the provider runs the server, the equivalent is a logical dump of your databases loaded into an 8.4 server - which is also how you move between hosts, covered in migrating MySQL to a new host. A logical dump also skips the 5.7-to-8.0 hop, since MySQL 8.4 loads a 5.7 dump directly in most cases; the exceptions are mostly reserved words and zero dates under strict mode.

An upgrade, step by step#

For a self-managed server, the in-place route from 8.0 looks like this. Each step has a reason, and skipping one is how upgrades turn into restores.

  1. Get to a recent 8.0 patch first. Upgrading from 8.0.40-something is better tested than from 8.0.20, and the late 8.0 patches warn about most of what 8.4 removes. Read the error log after that restart for deprecation warnings: each one is a future failure.
  2. Run the upgrade checker against the running server and fix everything it reports as an error. Warnings deserve a look too; they include accounts on mysql_native_password.
  3. Clean the configuration. Remove the options listed above, and decide deliberately about the changed InnoDB defaults: if you had tuned innodb_io_capacity for your storage, your value stays; if you never set it, it jumps from 200 to 10000.
  4. Take a full backup you have restored at least once. A logical dump is the one that lets you go back to 8.0 if you must, because an in-place upgrade cannot be reversed by starting the old binaries - the data dictionary has been upgraded.
  5. Shut down cleanly. With innodb_fast_shutdown at its default of 1 a clean shutdown is fine; setting it to 0 first makes InnoDB finish purge and merge work before stopping, which some people prefer before a major upgrade.
  6. Install 8.4 and start it on the same data directory. Watch the error log: the server upgrades the data dictionary, then the system schema, and reports when it is ready for connections. On a large instance with many tables this takes a while; do not interrupt it.
  7. Test the application, including logins for every account, the scheduled jobs, and any monitoring that runs administrative statements. The failures in this upgrade are almost all in the edges, not in the queries.

On a hosted database you do not do steps 5 and 6 yourself, and the route is a dump from the old server loaded into a new 8.4 one. Steps 1 to 4 and 7 still apply, and the upgrade checker can be pointed at your old server from any machine with MySQL Shell. When the application works against a rehearsal copy loaded from the dump, the cut-over is a configuration change.

What does not change#

For the application, most things. SQL syntax for queries and DML is the same. utf8mb4 with utf8mb4_0900_ai_ci remains the default. Window functions, common table expressions, JSON functions, EXPLAIN ANALYZE, invisible and functional indexes all behave as in late 8.0. ORMs that supported 8.0 support 8.4; the ones to check are those that issue replication or administration statements, and those pinned to an old driver.

The checklist, in order: upgrade the drivers, move accounts off mysql_native_password, remove removed options from configuration, replace removed statements in scripts and monitoring, run the upgrade checker, then rehearse the move on a copy and run the application's test suite against it.

FAQ#

Is MySQL 8.0 still supported?

No. MySQL 8.0 reached end of life in April 2026 and no longer receives fixes, including security fixes, from Oracle. Some cloud providers sell paid extended support for it, but the supported free path is 8.4 LTS.

Should I use MySQL 8.4 or a 9.x Innovation release?

For a production application, 8.4 LTS. Innovation releases are supported only until the next one, roughly a quarter, so staying on one means upgrading several times a year through releases that may remove things. Use 9.x to test what is coming, and move to the next LTS when it arrives.

Can I still use mysql_native_password on 8.4?

Only if the server is started with mysql_native_password=ON, which needs control of the server's configuration. Even then it is a stopgap: MySQL 9.0 removed the plugin. Move the account to caching_sha2_password and upgrade any driver that cannot handle it.

Will my 8.0 dump load into MySQL 8.4?

Almost always, yes. A logical dump from 8.0 loads into 8.4 without changes in the vast majority of cases. Watch for definer clauses naming accounts that do not exist on the new server, and for SET @@GLOBAL lines that need privileges an ordinary user lacks; mysqldump backup and restore covers both.

Do I need to run mysql_upgrade after upgrading?

No - and on 8.4 you cannot, because it was removed. Since 8.0.16 the server upgrades its own system tables and data dictionary at start-up, controlled by the --upgrade option, which defaults to doing whatever is necessary.


Comments

Completely anonymous: no account, no email, no cookie. We store the name you type, the text and the time - nothing else. Links are limited and markup is not rendered.

0/2000