MySQL 5.7 reached end of life in October 2023, and plenty of production fleets are still on it — usually because the last upgrade attempt hit something sharp. The 5.7→8.0 jump is the biggest behavioral change MySQL has shipped in a decade. These are the traps we check for before any cutover, in the order they usually bite.
1. There is no downgrade
Once 8.0 starts on a 5.7 data directory it rewrites the data dictionary, and there is no supported path back. That one fact should shape the whole plan: upgrade a replica (or a restored snapshot), never the primary in place. Build an 8.0 replica off the 5.7 primary, let the application read against it, and cut over by promotion — which also hands you a rollback plan (the untouched 5.7 primary) for the first days after cutover.
Run mysqlsh util.checkForServerUpgrade() against the 5.7 instance first; it catches most of what follows mechanically.
2. The default collation changed
8.0's default character set is utf8mb4 with collation utf8mb4_0900_ai_ci; 5.7's utf8mb4 default was utf8mb4_general_ci. New tables created on 8.0 get the new collation, and comparing columns across collations either errors ("Illegal mix of collations") or — worse — silently stops using indexes on joins.
Decide the target collation before migrating, set it explicitly in server config and in every CREATE TABLE, and audit existing columns:
SELECT table_name, column_name, collation_name
FROM information_schema.columns
WHERE table_schema = 'yourdb' AND collation_name LIKE 'utf8%'
GROUP BY 1,2,3;
Mixed-collation joins are the single most common post-upgrade performance regression we see.
3. Reserved words and removed syntax
8.0 reserves words that 5.7 did not — groups, rank, window, lateral, system among them. A column or table with one of those names breaks unquoted queries. GROUP BY ... ASC/DESC syntax is gone (use ORDER BY), and the query cache no longer exists — any application code setting SQL_NO_CACHE or sizing query_cache_size needs cleanup. If your workload actually benefited from the query cache (rare, but real for read-heavy, low-churn tables), plan an application-side cache before, not after, cutover.
4. Authentication plugin mismatches
8.0's default auth plugin is caching_sha2_password. Old client libraries — PHP 5-era drivers, old JDBC, anything linked against ancient libmysqlclient — cannot speak it and fail with "Authentication plugin not supported." Inventory every client (applications, cron jobs, monitoring agents, BI tools) before cutover. You can hold the default at mysql_native_password during the transition, but treat that as a bridge with an end date, not a destination — 8.4 deprecates it outright.
5. The optimizer changed underneath you
Most queries get faster on 8.0; a few get dramatically slower, and those few are what pages you at 2 a.m. Common cases: derived-table merging changing join orders, and different index choices on queries that were only ever marginally fine. The defense is empirical, not theoretical:
- Capture the top ~200 query digests from 5.7's Performance Schema.
- Replay them against the 8.0 replica and diff latency and rows examined.
- For true regressions, fix the index or query; reach for optimizer hints only when a fix cannot ship before cutover.
Budget real calendar time for this step. It is the difference between an upgrade and a gamble.
6. Operational defaults that surprise
innodb_flush_neighborsand redo-log defaults changed; retune rather than carrying 5.7 values forward blindly.- 8.0 removed
innodb_file_formatand friends — config files carrying dead variables fail startup. Strip unknown variables frommy.cnfand re-derive the config instead of copying it. - Binary log is on by default in 8.0; a standalone server that never had it enabled suddenly grows binlogs. Set expiration (
binlog_expire_logs_seconds) or disable deliberately. GROUP BYno longer implies sorting; code that accidentally relied on ordered grouped results returns rows in a new order. That is an application bug 8.0 merely exposes — but exposure day should not be cutover day.
The shape of a safe upgrade
Every low-drama 5.7→8.0 migration we have run looks the same: upgrade checker, collation decision, client inventory, an 8.0 replica under real read traffic for one to two weeks, a digest-level performance diff, then a promoted cutover with the old primary held warm as rollback. None of it is glamorous. All of it is cheaper than the incident you get by skipping it.