MySQL Reference

MySQL administration and the key differences from PostgreSQL.

Connection and CLI

Connect with the mysql client
# Local connection
mysql -u root -p myapp

# Remote connection
mysql -h db.example.com -u appuser -p myapp

# Execute and exit
mysql -u root -e "SHOW DATABASES;"
Useful commands inside the mysql shell
mysql -u root -p <<'SQL'
SHOW DATABASES;
USE myapp;
SHOW TABLES;
DESCRIBE devices;               -- column names, types, keys
SHOW CREATE TABLE devices\G     -- full CREATE statement (\G vertical)
SHOW INDEX FROM devices;
SHOW PROCESSLIST;
STATUS;                          -- connection info, uptime, version
SQL

\G at the end of a statement displays results vertically — one field per line. Useful for wide tables.

Database and User Management

Create database and user
CREATE DATABASE myapp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

CREATE USER 'appuser'@'%' IDENTIFIED BY 'changeme';
GRANT ALL PRIVILEGES ON myapp.* TO 'appuser'@'%';
FLUSH PRIVILEGES;
Read-only user
CREATE USER 'readonly'@'%' IDENTIFIED BY 'changeme';
GRANT SELECT ON myapp.* TO 'readonly'@'%';
FLUSH PRIVILEGES;
Show grants for a user
SHOW GRANTS FOR 'appuser'@'%';

MySQL vs PostgreSQL Differences

Key syntax differences you will encounter when moving between the two:

AUTO_INCREMENT vs SERIAL
-- MySQL
CREATE TABLE devices (
    id          INT AUTO_INCREMENT PRIMARY KEY,
    hostname    VARCHAR(255) NOT NULL,
    created_at  TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;

-- PostgreSQL equivalent
CREATE TABLE devices (
    id          SERIAL PRIMARY KEY,
    hostname    VARCHAR(255) NOT NULL,
    created_at  TIMESTAMPTZ DEFAULT NOW()
);
LIMIT with OFFSET
-- MySQL: LIMIT offset, count
SELECT * FROM devices LIMIT 20, 10;

-- Standard SQL (also works in MySQL 8+): LIMIT count OFFSET skip
SELECT * FROM devices LIMIT 10 OFFSET 20;
String quoting
-- MySQL: backticks for identifiers, single or double quotes for strings
SELECT `hostname` FROM `devices` WHERE `type` = 'switch';

-- PostgreSQL: double quotes for identifiers, single quotes for strings
SELECT "hostname" FROM "devices" WHERE "type" = 'switch';

Storage Engines

InnoDB vs MyISAM
-- Check engine for a table
SHOW TABLE STATUS WHERE Name = 'devices';

-- Convert to InnoDB (always prefer InnoDB)
ALTER TABLE legacy_table ENGINE = InnoDB;

InnoDB: transactions, row-level locking, foreign keys, crash recovery. Use InnoDB for everything. MyISAM is legacy — no transactions, table-level locking, no FK enforcement.

Backup and Restore

mysqldump — logical backup
# Single database
mysqldump -u root -p myapp > myapp_$(date +%F).sql

# Single database, compressed
mysqldump -u root -p myapp | gzip > myapp_$(date +%F).sql.gz

# Schema only
mysqldump -u root -p --no-data myapp > schema.sql

# Specific table
mysqldump -u root -p myapp devices > devices.sql

# All databases
mysqldump -u root -p --all-databases > full_$(date +%F).sql
Restore from dump
mysql -u root -p myapp < myapp_2026-04-10.sql

# Compressed
zcat myapp_2026-04-10.sql.gz | mysql -u root -p myapp

Performance

EXPLAIN — query execution plan
EXPLAIN SELECT * FROM orders WHERE customer_id = 42;

-- With actual execution stats (MySQL 8.0.18+)
EXPLAIN ANALYZE SELECT * FROM orders WHERE customer_id = 42;

Key columns in EXPLAIN output:

  • type: ALL (full scan, bad), ref (index lookup, good), const (single row, best)

  • key: which index is used, NULL means no index

  • rows: estimated rows examined

Show slow query log status
SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';

-- Enable temporarily
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 2;  -- seconds

Variables and Status

Server variables and status counters
-- Current settings
SHOW VARIABLES LIKE 'max_connections';
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';

-- Runtime stats
SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW GLOBAL STATUS LIKE 'Uptime';