Why MariaDB has its own setting
MariaDB began as a MySQL fork and still reads text the same way: identifiers in backticks, strings in single or double quotes, backslash escapes such as 'can\'t', and # line comments. Where the two differ is grammar. MariaDB has had DELETE … RETURNING since 10.0 and INSERT … RETURNING since 10.5, and the MariaDB setting treats RETURNING as a clause. With the MySQL setting the same statement still formats, but returning cart_id, sku is glued onto the end of the WHERE condition and left in lower case.
So choose by server, not by habit. A query written for MariaDB 10.6 or 11.x belongs under MariaDB; one that must also run on MySQL 8 is better checked under MySQL, since that is the stricter target for RETURNING and sequences.
Sequences, temporal tables and JSON
NEXTVAL(invoice_seq), LASTVAL(invoice_seq) and NEXT VALUE FOR invoice_seq format as ordinary expressions inside SELECT and INSERT lists. CREATE SEQUENCE itself is laid out less neatly: START WITH 1000 is split so that WITH begins a new line, as if a CTE followed. The statement is unchanged apart from whitespace, so it still runs.
For system-versioned tables, FOR SYSTEM_TIME AS OF TIMESTAMP '2026-03-01 00:00:00', BETWEEN … AND … and ALL stay on the same line as the table name, which keeps a point-in-time query easy to scan. WITH SYSTEM VERSIONING at the end of a CREATE TABLE lands on a WITH line of its own. Application-time periods are less lucky: in FOR PORTION OF valid_period FROM … TO …, the FROM is mistaken for a new FROM clause.
JSON_TABLE(items, '$[*]' COLUMNS (…)) is expanded with one column definition per line, and INTERSECT and EXCEPT separate their two queries cleanly.
Upserts, procedures and executable comments
MariaDB has no AS new row alias for ON DUPLICATE KEY UPDATE, so upserts refer to the incoming row with VALUES(col) or its synonym VALUE(col). Prefer VALUE(qty) when formatting: the plural form is read as the start of a VALUES clause and gets broken across lines, while the singular stays inline.
Stored routines format best without DELIMITER. With DELIMITER $$, the closing END $$ and the next DELIMITER ; end up on one line, so remove those client commands first. The body statements between BEGIN and END are each laid out, though not indented under BEGIN.
One caveat for Minify: the generic /*! … */ executable comment is preserved, but MariaDB’s own /*M!100500 … */ form is treated as an ordinary comment and removed. Keep such statements in formatted form, or check the minified output before using it.
Useful options
Commas → Leading suits long INSERT column lists and multi-row VALUES. Function case → UPPER makes JSON_VALUE and DATE_FORMAT stand out from column names. To look for unclosed quotes or brackets without changing the layout, open the SQL validator; to squeeze a query onto one line, the SQL minifier does only that.
Examples
Bulk customer insert returning new IDs
INSERT … RETURNING laid out as its own clause, with leading commas in the value rows and the returned columns.
insert into customers (email, country, signup_source) values ('[email protected]', 'PT', 'web'), ('[email protected]', 'SG', 'app') returning id, email, created_at;INSERT INTO
customers (email, country, signup_source)
VALUES
('[email protected]', 'PT', 'web')
, ('[email protected]', 'SG', 'app')
RETURNING
id
, email
, created_at;
Price history at a point in time
A system-versioned table queried with FOR SYSTEM_TIME AS OF, which stays on the FROM line.
select p.sku, p.amount, p.row_start from prices for system_time as of timestamp '2026-03-01 00:00:00' as p where p.sku like 'SKU-1%' order by p.sku;SELECT
p.sku,
p.amount,
p.row_start
FROM
prices FOR system_time AS of TIMESTAMP '2026-03-01 00:00:00' AS p
WHERE
p.sku LIKE 'SKU-1%'
ORDER BY
p.sku;
Order lines from a JSON column
JSON_TABLE with a COLUMNS list, expanded one column definition per line.
select o.id as order_id, jt.sku, jt.qty from orders o, json_table(o.items, '$[*]' columns (sku varchar(32) path '$.sku', qty int path '$.qty')) as jt where o.created_at >= '2026-01-01' and jt.qty > 1;SELECT
o.id AS order_id,
jt.sku,
jt.qty
FROM
orders o,
json_table (
o.items,
'$[*]' columns (
sku VARCHAR(32) path '$.sku',
qty INT path '$.qty'
)
) AS jt
WHERE
o.created_at >= '2026-01-01'
AND jt.qty > 1;
Stock upsert using VALUE()
A # comment and an ON DUPLICATE KEY UPDATE that refers to the incoming row with VALUE(qty).
# nightly stock sync
insert into inventory (sku, warehouse_id, qty) values ('SKU-1001', 3, 40), ('SKU-1002', 3, 12) on duplicate key update qty = qty + value(qty), updated_at = now();# nightly stock sync
INSERT INTO
inventory (sku, warehouse_id, qty)
VALUES
('SKU-1001', 3, 40),
('SKU-1002', 3, 12)
ON DUPLICATE KEY UPDATE
qty = qty + value (qty),
updated_at = now();
Common errors and how to fix them
| Error | Cause | Fix |
|---|---|---|
This string is never closed — the ' has no matching 'Explained | A string ends in a backslash, as in 'D:\exports', so the final quote is escaped instead of closing the string. | Escape the trailing backslash as \, or build the path with CONCAT so no literal ends in a backslash. |
"::int" is not valid MariaDB syntax | A Postgres cast shorthand was carried over into a MariaDB query. | Use CAST(qty AS INT) or CONVERT(qty, SIGNED) instead of the :: operator. |
"[Order" is not valid MariaDB syntax | Bracket-quoted names from SQL Server were pasted in; MariaDB quotes names with backticks. | Replace the brackets with backticks, or select the T-SQL (SQL Server) dialect if the query is meant for SQL Server. |
This '(' is never closedExplained | A JSON_TABLE COLUMNS list or nested function call is one closing parenthesis short. | Close the innermost open bracket first, working outwards from the position shown. |
Frequently asked questions
Is MariaDB SQL formatted differently from MySQL?
Strings, quotes and comments are read identically. The difference is in MariaDB-only grammar such as RETURNING, which only the MariaDB setting lays out as a clause.
Can I format queries on system-versioned tables?
Yes. FOR SYSTEM_TIME AS OF, BETWEEN and ALL are kept beside the table name, and WITH SYSTEM VERSIONING is accepted in CREATE TABLE.
Does it work with HeidiSQL or DBeaver exports?
Yes, as long as you paste plain SQL. Remove DELIMITER lines from routine exports before formatting, then add them back.
Will minifying keep my /*M! */ version comments?
No. Minify keeps /*! / and /+ */ comments but strips /*M! */ ones, so use formatted output for scripts that rely on them.
Where does my SQL go when I format it?
Nowhere. The MariaDB rules and the formatter are bundled into the page and run locally in your browser.