Installation, databases, users and engines
Get a server running, create a database and a least-privilege account, and know which storage engine is actually holding your rows.
Install and connect
MySQL is a client/server system: mysqld owns the data directory and every tool is a client speaking the wire protocol. Installing means installing both parts and initialising the data directory before the daemon starts.
# Debian / Ubuntu
sudo apt install mysql-server
sudo systemctl enable --now mysql
sudo mysql_secure_installation # root password, removes anonymous accounts
# Docker, fastest for local experiments
docker run --name mysql -e MYSQL_ROOT_PASSWORD=secret -p 3306:3306 -d mysql:8.4
# Client
mysql -h 127.0.0.1 -P 3306 -u app -p
mysql -u app -p -e "SELECT VERSION();" # one statement, script friendly- Use
127.0.0.1rather thanlocalhostin scripts:localhostcan be routed through a Unix socket instead of TCP, which changes which host rules apply. - Server settings live in
/etc/mysql/my.cnf(plus files undermy.cnf.d/). After editing, restart and read the error log rather than guessing why the daemon refused to start. - The default port is 3306. Bind it to a private interface or a firewall rule, never to the public internet.
Databases, tables and users
A MySQL account is not just a name: it is a name plus a host pattern, and 'app'@'localhost', 'app'@'10.0.0.%' and 'app'@'%' are three different accounts with independent passwords and grants.
CREATE DATABASE app CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
CREATE USER 'app'@'10.0.0.%' IDENTIFIED BY 'a-long-random-password';
GRANT SELECT, INSERT, UPDATE, DELETE ON app.* TO 'app'@'10.0.0.%';
SHOW GRANTS FOR 'app'@'10.0.0.%';
SHOW CREATE TABLE app.orders;
-- change a password (MySQL 8 syntax)
ALTER USER 'app'@'10.0.0.%' IDENTIFIED BY 'a-newer-longer-password';| Concept | What it really is |
|---|---|
| Database | A namespace of tables; in MySQL schema and database are synonyms |
| Account | user plus a host pattern, matched at connection time |
| Privilege | A grant on a scope: global, database, table or column |
| Default engine | InnoDB unless the table or server says otherwise |
Use utf8mb4 everywhere. MySQL's older utf8 is a three-byte subset that cannot store emoji or many CJK extension characters, and mixing the two in a join silently forces slow conversions.
Storage engines
| Engine | Transactions | Where it still makes sense |
|---|---|---|
| InnoDB | Yes — row locks + MVCC | Default; essentially all application tables |
| MyISAM | No — table-level locks | Legacy read-mostly tables; avoid in new work |
| MEMORY | No — data lost on restart | Small temporary lookup tables |
| ARCHIVE | No — insert and compress only | Long retention of write-once logs |
| NDB | Yes (distributed) | MySQL Cluster deployments |
innodb_buffer_pool_size is the single most important setting: it decides how much of your working set stays cached in RAM. Sizing it at roughly half to three quarters of available memory beats almost any query tweak.Check what a table is using with SHOW TABLE STATUS LIKE 'orders' or SELECT ENGINE FROM information_schema.tables WHERE table_name = 'orders'.
FAQ
Should I use MySQL or MariaDB?
Why does my connection fail with 'Access denied' when the password is right?
user@host row; check SELECT user, host FROM mysql.user.Related
Indexes and reading EXPLAIN Replication, backup and operational pitfalls
Last refreshed 2026-09-18.