SQL modes and strictness

MySQL · Essentials · 8 min

Non-strict MySQL silently truncates and invents data; many legacy bugs come from relaxed SQL modes.

The sql_mode system variable changes how MySQL validates data and SQL. The 8.x default is:

ONLY_FULL_GROUP_BY, STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_ENGINE_SUBSTITUTION

The two that matter most:

  • STRICT_TRANS_TABLES: invalid or out-of-range values cause an error instead of being silently adjusted. Without it, inserting 'abc' into an INT stores 0, a 300-character string into VARCHAR(255) is truncated, and '2026-02-30' becomes '0000-00-00' — each with only a warning that applications never read.
  • ONLY_FULL_GROUP_BY: rejects queries that select a column that is neither grouped nor aggregated (unless it is functionally dependent on the grouped key). Without it, MySQL returns a value from an arbitrary row of each group — nondeterministic results.

Old applications sometimes break on upgrade and "fix" it by clearing sql_mode. Don't: fix the queries instead. If you truly need an arbitrary value from a group, say so with ANY_VALUE(col).

Check the active mode with SELECT @@SESSION.sql_mode;. Set it globally in the config file (sql_mode = ... under [mysqld]) and avoid per-session overrides, so every client gets the same behaviour.

Example

SELECT @@SESSION.sql_mode;
-- ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,...

CREATE TABLE t (n TINYINT, s VARCHAR(3));
INSERT INTO t VALUES (300, 'abcdef');
-- ERROR 1264 (22003): Out of range value for column 'n' at row 1

SET SESSION sql_mode = '';                -- what NOT to do
INSERT INTO t VALUES (300, 'abcdef');     -- Query OK, 1 row affected, 2 warnings
SELECT * FROM t;                          -- 127 | abc   (silently mangled)
SET SESSION sql_mode = DEFAULT;

CREATE TABLE emp (dept VARCHAR(10), name VARCHAR(20));
SELECT dept, name FROM emp GROUP BY dept;
-- ERROR 1055: ... not in GROUP BY clause ... incompatible with sql_mode=only_full_group_by
SELECT dept, ANY_VALUE(name) FROM emp GROUP BY dept;   -- explicit, allowed

Remember

  • STRICT_TRANS_TABLES turns silent truncation into errors
  • ONLY_FULL_GROUP_BY prevents nondeterministic GROUP BY results
  • Keep the defaults; fix queries instead of relaxing sql_mode

Watch out for

  • Clearing sql_mode to make a legacy app work, then storing corrupted values unnoticed.

Check yourself

  1. Without STRICT mode, what happens when inserting 300 into a TINYINT column?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: dev.mysql.com/doc/refman/8.4/en/sql-mode.html

Builds on

Unlocks

Nothing builds on this yet.