MySQL Cheat Sheet
Syntax
Server and client CTEs and window functions Transactions and locking Replication and backup
mysql -u user -p -h host -P 3306 dbname # connect
mysql -u user -p db < script.sql # run script
mysqldump --single-transaction --routines --events db > db.sql
mysqladmin -u root -p status | version | shutdown
sudo systemctl start|stop|status mysql # mysqld on RHELSELECT VERSION(); SHOW DATABASES; USE db; SHOW TABLES; DESCRIBE t; SHOW CREATE TABLE t\G
SHOW PROCESSLIST; KILL QUERY id; SHOW WARNINGS; SHOW VARIABLES LIKE '...'; SET PERSIST var = val;CREATE DATABASE db CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
CREATE TABLE t (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
code VARCHAR(20) NOT NULL UNIQUE,
amount DECIMAL(12,2) NOT NULL DEFAULT 0 CHECK (amount >= 0),
parent_id BIGINT UNSIGNED NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
KEY ix_t_parent (parent_id),
CONSTRAINT fk_t_parent FOREIGN KEY (parent_id) REFERENCES p (id)
) ENGINE = InnoDB;
ALTER TABLE t ADD COLUMN c INT NULL AFTER code, ALGORITHM = INSTANT;
ALTER TABLE t MODIFY c BIGINT NOT NULL; ALTER TABLE t RENAME COLUMN c TO d; ALTER TABLE t DROP COLUMN d;
CREATE INDEX ix ON t (a, b DESC); CREATE INDEX fx ON t ((LOWER(code))); ALTER TABLE t ALTER INDEX ix INVISIBLE;
DROP TABLE IF EXISTS t; TRUNCATE TABLE t; RENAME TABLE a TO b;INSERT INTO t (a, b) VALUES (1, 'x'), (2, 'y');
INSERT INTO t (a, b) VALUES (1, 'x') AS new ON DUPLICATE KEY UPDATE b = new.b; -- upsert
INSERT IGNORE INTO t ...; REPLACE INTO t ...;
INSERT INTO t (a, b) SELECT ...;
UPDATE t1 JOIN t2 ON t2.id = t1.id SET t1.x = t2.x WHERE ...;
UPDATE t SET x = x + 1 WHERE ... ORDER BY id LIMIT 1000;
DELETE t1 FROM t1 JOIN t2 ON ... WHERE ...;
LOAD DATA LOCAL INFILE 'f.csv' INTO TABLE t FIELDS TERMINATED BY ',' IGNORE 1 LINES (a, @b) SET b = STR_TO_DATE(@b, '%d/%m/%Y');
SELECT LAST_INSERT_ID(), ROW_COUNT();SELECT DISTINCT a, CONCAT(b, ' ', c) AS bc FROM t
WHERE x BETWEEN 1 AND 10 AND y IN ('A', 'B') AND z LIKE 'P0%' AND w IS NULL AND v <=> NULL
ORDER BY a DESC, id LIMIT 20 OFFSET 40;
SELECT k, COUNT(*), SUM(v), GROUP_CONCAT(n ORDER BY n SEPARATOR ',') FROM t GROUP BY k WITH ROLLUP HAVING COUNT(*) > 1;
SELECT ... FROM a JOIN b ON ... LEFT JOIN c ON ... ; -- no FULL OUTER JOIN: LEFT ... UNION RIGHT ...
SELECT ... WHERE EXISTS (SELECT 1 FROM ... WHERE ...);
SELECT ... FROM t, LATERAL (SELECT ... WHERE u.k = t.k ORDER BY ... LIMIT 1) x;
SELECT ... UNION ALL SELECT ...; ... INTERSECT ...; ... EXCEPT ...; -- 8.0.31+IFNULL(a, b) COALESCE(a, b, c) NULLIF(a, b) IF(c, x, y) CASE WHEN ... THEN ... ELSE ... END
CONCAT CONCAT_WS CHAR_LENGTH LENGTH SUBSTRING SUBSTRING_INDEX REPLACE TRIM LPAD UPPER LOWER REGEXP_LIKE
ROUND TRUNCATE CEIL FLOOR MOD POW ABS DIV
NOW() CURDATE() UTC_TIMESTAMP() DATE_ADD(d, INTERVAL 7 DAY) d - INTERVAL 1 MONTH DATEDIFF(d2, d1)
TIMESTAMPDIFF(MINUTE, t1, t2) DATE_FORMAT(d, '%Y-%m') STR_TO_DATE(s, fmt) LAST_DAY(d) CONVERT_TZ(t, '+00:00', '+05:30')
CAST(x AS SIGNED | UNSIGNED | DECIMAL(10,2) | DATE | CHAR | JSON) HEX UNHEX CONV(x, 16, 10)WITH RECURSIVE r AS (SELECT ... UNION ALL SELECT ... FROM r WHERE ...) SELECT * FROM r;
ROW_NUMBER() OVER (PARTITION BY p ORDER BY o) RANK() DENSE_RANK() NTILE(4)
LAG(x) OVER w LEAD(x) OVER w FIRST_VALUE(x) OVER w
SUM(x) OVER (ORDER BY d ROWS UNBOUNDED PRECEDING) -- running total
AVG(x) OVER (ORDER BY d ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) -- moving average
... WINDOW w AS (PARTITION BY p ORDER BY o)doc->'$.a' doc->>'$.a' JSON_EXTRACT JSON_SET JSON_REMOVE JSON_ARRAY_APPEND JSON_CONTAINS 'v' MEMBER OF (doc->'$.arr')
JSON_TABLE(doc, '$.items[*]' COLUMNS (n INT PATH '$.n')) AS jt
JSON_ARRAYAGG(x) JSON_OBJECTAGG(k, v)
ALTER TABLE t ADD c VARCHAR(20) AS (doc->>'$.c') VIRTUAL, ADD INDEX (c);START TRANSACTION; ... COMMIT; | ROLLBACK; SAVEPOINT s; ROLLBACK TO SAVEPOINT s;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SELECT ... FOR UPDATE [NOWAIT | SKIP LOCKED]; SELECT ... FOR SHARE;
SHOW ENGINE INNODB STATUS\G SELECT * FROM sys.innodb_lock_waits\GDELIMITER //
CREATE PROCEDURE p(IN a INT, OUT b INT) BEGIN DECLARE v INT DEFAULT 0; SELECT COUNT(*) INTO b FROM t WHERE x = a; END //
CREATE FUNCTION f(a INT) RETURNS INT DETERMINISTIC NO SQL RETURN a * 2 //
CREATE TRIGGER trg BEFORE INSERT ON t FOR EACH ROW BEGIN SET NEW.x = UPPER(NEW.x); END //
CREATE EVENT ev ON SCHEDULE EVERY 1 DAY DO DELETE FROM logs WHERE created_at < NOW() - INTERVAL 90 DAY //
DELIMITER ;
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '...';
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; RESIGNAL; END;Example
Which tool for which job:
INSERT... AS new ON DUPLICATE KEY UPDATE LOAD DATA [LOCAL] INFILE Top-N per group
ROW_NUMBER() in a CTE, or LATERAL... LIMIT WITH RECURSIVE FULLTEXT + MATCH... AGAINST JSON + generated-column index Retention of logs
Partitioning + DROP PARTITION via events CREATE EVENT Generated column + UNIQUE (NULLs allowed) FOR UPDATE SKIP LOCKED
Expected Result
You can write any common MySQL statement from this sheet in minutes.
Common Mistakes
Copying syntax that requires a newer MySQL version than you run — check SELECT VERSION();.
Best Practices
Annotate this sheet with your own team's conventions.
Practice Questions
Without looking, write an upsert, a LATERAL top-1 query, and a recursive CTE.