MariaDB’s SQL modes are a surprisingly powerful, yet often overlooked, mechanism for enforcing data integrity and predictability across your database.

Let’s see what happens when STRICT_TRANS_TABLES is enabled, and we try to insert a value that’s too large for a column:

CREATE TABLE `products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  `price` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

-- With STRICT_TRANS_TABLES enabled:
INSERT INTO `products` (`name`, `price`) VALUES ('Super Widget', '9999999999.99');

This will result in an error: ERROR 1264 (22003): Out of range value for column 'price' at row 1. Without strict mode, MariaDB would have silently truncated the value or inserted a default, leading to data corruption.

At its core, SQL mode is a set of flags that tell MariaDB how strictly to adhere to SQL standards and how to handle invalid data. When you enable a strict mode, you’re essentially telling MariaDB, "Don’t be lenient; if something is wrong, tell me about it immediately." This prevents silent data corruption and unexpected behavior that can arise from implicit type conversions or invalid data insertions.

The primary benefit is data integrity. By enforcing strict validation, you ensure that only valid, well-formed data enters your database. This reduces bugs in your application that might stem from unexpected data types or values. It also makes your database behavior more predictable, as it won’t surprise you with implicit data coercions that might not be what you intended.

Consider a scenario where you have a users table with an is_active boolean column. In non-strict mode, inserting 'yes' or 1 might both work, but what about 'maybe'? Strict mode clarifies these expectations.

Here’s how MariaDB processes statements based on the active SQL modes. When a statement is executed, MariaDB checks the incoming data against the column definitions and the active SQL modes. If a violation occurs (e.g., inserting text into a numeric column, a value out of range, or a date that doesn’t exist), the behavior is dictated by the mode. Strict modes like STRICT_TRANS_TABLES or STRICT_ALL_TABLES will cause the statement to fail with an error. Other modes might allow the operation but issue a warning, or silently adjust the data.

The most common and impactful strict modes are:

  • STRICT_TRANS_TABLES: This is the workhorse for transactional tables (like InnoDB). If you try to insert or update data that is invalid for a column (e.g., out of range, wrong data type, or a date like '2023-02-30'), the statement will be rejected with an error. For non-transactional tables (like MyISAM), it behaves like TRADITIONAL.
  • STRICT_ALL_TABLES: This is even stricter. It applies the same behavior as STRICT_TRANS_TABLES to all tables, including non-transactional ones. This is generally the most robust option for ensuring data integrity everywhere.
  • TRADITIONAL: This mode is a shorthand for STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, NO_ENGINE_SUBSTITUTION. It’s a good starting point for a highly compliant and strict setup.

Let’s look at enabling STRICT_TRANS_TABLES globally. You can do this in your my.cnf or my.ini file under the [mysqld] section:

[mysqld]
sql_mode = "STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION"

Or, for a more comprehensive set:

[mysqld]
sql_mode = "STRICT_ALL_TABLES,ONLY_FULL_GROUP_BY,NO_ZERO_IN_DATE,NO_ZERO_DATE,NO_ENGINE_SUBSTITUTION"

After restarting the MariaDB server, this setting will be active. You can also set it for the current session without restarting:

SET SESSION sql_mode = 'STRICT_TRANS_TABLES';

This is incredibly useful for testing changes before applying them globally.

Consider inserting a string into an integer column. Without strict mode, MariaDB might try to convert it. With STRICT_TRANS_TABLES or STRICT_ALL_TABLES, it will fail.

-- Assume 'age' is an INT column
INSERT INTO `users` (`age`) VALUES ('twenty');
-- With strict mode: ERROR 1366 (HY000): Incorrect integer value: 'twenty' for column 'age' at row 1

Similarly, inserting an invalid date:

-- Assume 'birth_date' is a DATE column
INSERT INTO `users` (`birth_date`) VALUES ('2023-02-30');
-- With strict mode: ERROR 1292 (22008): Incorrect date value: '2023-02-30' for column 'birth_date' at row 1

The real power comes from understanding how different modes interact. For example, NO_ZERO_IN_DATE prevents dates like '2023-00-15' and NO_ZERO_DATE prevents '0000-00-00'. When combined with STRICT_TRANS_TABLES, these become hard errors rather than warnings or silent adjustments.

The ONLY_FULL_GROUP_BY mode is another critical component for correctness. It enforces that whenever you use GROUP BY, any column in the SELECT list that is not an aggregate function must be included in the GROUP BY clause. This prevents ambiguous results where the database might pick an arbitrary value from a group for a non-aggregated column.

-- Without ONLY_FULL_GROUP_BY, this might run but give unpredictable results:
SELECT department, AVG(salary) FROM employees GROUP BY department;

-- With ONLY_FULL_GROUP_BY, you'd get an error unless you add employee_id to GROUP BY:
SELECT department, employee_id, AVG(salary) FROM employees GROUP BY department; -- ERROR
SELECT department, AVG(salary) FROM employees GROUP BY department; -- OK
SELECT department, employee_id, AVG(salary) FROM employees GROUP BY department, employee_id; -- OK

The NO_ENGINE_SUBSTITUTION mode is also vital. It prevents MariaDB from automatically choosing a different storage engine (like MyISAM) if the requested engine (like InnoDB) is unavailable. This ensures you’re using the engine you intended, avoiding subtle performance or feature differences.

When you encounter an error like ERROR 1366 (HY000): Incorrect ... value: '...' for column '...' at row 1, it’s almost always a SQL mode issue. The fix isn’t to change the data to fit the lenient old behavior, but to align your data input and schema with the strictness you desire. This means ensuring your application code is inserting valid data types and values, or adjusting your sql_mode setting to allow the data if it’s truly acceptable for your use case (though this is generally discouraged).

The next thing you’ll run into after wrestling with SQL modes is how they interact with INSERT ... ON DUPLICATE KEY UPDATE statements, especially regarding the order of operations and which specific modes might still allow partial updates or warnings.

Want structured learning?

Take the full Mariadb course →