When MySQL 8 Stopped Respecting Implicit Ordering
Back to Blog

When MySQL 8 Stopped Respecting Implicit Ordering

I spent a good amount of time fixing issues that showed up after upgrading a database from MySQL 5.7 to MySQL 8. The upgrade itself went smoothly, but several queries started behaving differently because parts of the application were relying on implicit row ordering without explicitly defining it.

What Changed

MySQL 8 does not introduce a new "ordering rule". The real change is that it removes the accidental stability that older applications sometimes depended on.

The optimizer now has more freedom in how it executes queries, including:

  • different join strategies
  • hash-based grouping and joins
  • different index choices based on statistics
  • more parallel execution paths

As a result:

Row order is no longer stable unless it is explicitly defined using ORDER BY.

Example 1: GROUP BY no longer implies ordering

SELECT DATE(created_at), COUNT(*)
FROM orders
GROUP BY DATE(created_at);

In MySQL 5.7, this often appeared sorted by date because index-driven execution frequently preserved order.

In MySQL 8, grouping may use hash-based execution, which does not preserve order, so the same query can return dates in an arbitrary sequence.

Fix:

SELECT DATE(created_at), COUNT(*)
FROM orders
GROUP BY DATE(created_at)
ORDER BY DATE(created_at);

Example 2: LIMIT with ties is not deterministic

SELECT *
FROM posts
ORDER BY score DESC
LIMIT 10;

When multiple rows share the same score, MySQL is free to return any subset of those tied rows first.

In MySQL 5.7, the result often looked stable due to consistent index usage. In MySQL 8, execution plans can change more easily, so the order among ties can vary between runs.

Fix:

SELECT *
FROM posts
ORDER BY score DESC, id ASC;

Key Lesson

If row order matters, it must be explicitly defined with ORDER BY. Everything else is an execution detail, not a guarantee.