SynfraCore
Synfracore
Start Learning
Navigation

Academies

Platform

RoadmapsLabsCertificationsInterviewPYQsAI AssistantCareer
Start Learning Free🗺️ Learning Roadmaps

MySQLFundamentals

Core concepts and commands — hands-on from the start

✍️
Written by senior engineers. Reviewed for technical accuracy.· Updated 2025 · SynfraCore MySQL Team
Expert Content

MySQL — Fundamentals

Setup and Connection

bash
# Docker — quickest setup
# 8.0 is an older LTS series — prefer 8.4 (LTS) or 9.x (Innovation) for new work
# *(needs verification — check Oracle's current MySQL Lifetime Support page for 8.0's exact end-of-support date before relying on it)*
docker run -d --name mysql \
    -e MYSQL_ROOT_PASSWORD=rootpass \
    -e MYSQL_DATABASE=myapp \
    -e MYSQL_USER=appuser \
    -e MYSQL_PASSWORD=apppass \
    -p 3306:3306 \
    mysql:8.4

# Connect
mysql -h 127.0.0.1 -u appuser -p myapp
mysql -u root -p  # then type password

# Useful commands inside MySQL
SHOW DATABASES;
USE myapp;
SHOW TABLES;
DESCRIBE users;
SHOW CREATE TABLE users\G    # \G = vertical output
SHOW PROCESSLIST;            # Running queries
SHOW STATUS LIKE 'Threads%';

MySQL-Specific Features

sql
-- AUTO_INCREMENT (MySQL's SERIAL equivalent)
CREATE TABLE users (
    id         BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    email      VARCHAR(255) NOT NULL,
    username   VARCHAR(50) NOT NULL,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (id),
    UNIQUE KEY uk_email (email),
    INDEX idx_username (username)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- ENUM type (MySQL-specific, avoid in portable SQL)
CREATE TABLE orders (
    id     BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    status ENUM('pending','processing','shipped','delivered','cancelled') DEFAULT 'pending'
);

-- JSON column (MySQL 5.7.8+)
CREATE TABLE products (
    id         BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name       VARCHAR(255) NOT NULL,
    attributes JSON
);

INSERT INTO products (name, attributes)
VALUES ('Laptop', '{"brand":"Dell","ram":16,"storage":512}');

-- Query JSON
SELECT name, JSON_EXTRACT(attributes, '$.brand') AS brand
FROM products;
-- Or using ->> shorthand (unquoted)
SELECT name, attributes->>'$.brand' AS brand FROM products;

InnoDB Storage Engine

sql
-- InnoDB is default and required for:
-- - ACID transactions
-- - Foreign keys
-- - Row-level locking (vs table-level in MyISAM)

-- Transactions
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;
-- On error:
ROLLBACK;

-- Savepoints
START TRANSACTION;
UPDATE inventory SET qty = qty - 1 WHERE product_id = 5;
SAVEPOINT after_inventory;
INSERT INTO order_items (order_id, product_id, qty) VALUES (100, 5, 1);
-- If order item insert fails:
ROLLBACK TO after_inventory;
COMMIT;

-- Isolation levels
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- READ UNCOMMITTED: dirty reads allowed (never use)
-- READ COMMITTED:   no dirty reads (PostgreSQL default)
-- REPEATABLE READ:  no dirty or non-repeatable reads (MySQL default)
-- SERIALIZABLE:     strictest, slowest

Performance Tuning

sql
-- EXPLAIN — understand query execution
EXPLAIN SELECT * FROM orders WHERE user_id = 1 AND status = 'pending';
EXPLAIN FORMAT=JSON SELECT ...\G  -- Detailed JSON output

-- Key fields in EXPLAIN:
-- type: system > const > ref > range > index > ALL (ALL = bad, full scan)
-- key: which index is used (NULL = no index used)
-- rows: estimated rows to examine
-- Extra: "Using index" = good, "Using filesort" = possible issue

-- Slow query log
SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 1;   -- Log queries > 1 second
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';

-- pt-query-digest to analyze slow log
pt-query-digest /var/log/mysql/slow.log | head -100

-- Index hints
SELECT * FROM orders FORCE INDEX (idx_user_status)
WHERE user_id = 1 AND status = 'pending';

Replication Setup

MySQL renamed its replication terminology and commands starting in 8.0.23 (CHANGE MASTER TOCHANGE REPLICATION SOURCE TO, START/STOP SLAVESTART/STOP REPLICA, SHOW SLAVE STATUSSHOW REPLICA STATUS, SHOW MASTER STATUSSHOW BINARY LOG STATUS) and the old master/slave syntax was later removed in the 8.4 LTS release — use the current names below; the old ones will error on a recent install even though a lot of tutorials online still show them.

ini
# Source (primary) my.cnf
[mysqld]
server-id = 1
log-bin = mysql-bin
binlog-format = ROW
binlog-do-db = myapp

# Replica my.cnf
[mysqld]
server-id = 2
relay-log = relay-bin
read-only = 1
sql
-- On the source: create replication user
CREATE USER 'replicator'@'%' IDENTIFIED BY 'repl_password';
GRANT REPLICATION SLAVE ON *.* TO 'replicator'@'%';  -- privilege name itself is unchanged
SHOW BINARY LOG STATUS;  -- note File and Position

-- On the replica: configure and start
CHANGE REPLICATION SOURCE TO
    SOURCE_HOST='source_host',
    SOURCE_USER='replicator',
    SOURCE_PASSWORD='repl_password',
    SOURCE_LOG_FILE='mysql-bin.000001',  -- from SHOW BINARY LOG STATUS
    SOURCE_LOG_POS=154;
START REPLICA;
SHOW REPLICA STATUS\G  -- check Seconds_Behind_Source = 0
Share:
Join our Community
Daily tips, job alerts, interview help — join engineers learning together
Up Next
MySQLIntermediate
Real-world patterns, best practices, and deeper topics
Also Worth Exploring
← Back to all MySQL modules
InstallationIntermediate