Установка и настройка
Способы установки
Три варианта:
- Apt / yum — из репозитория ОС.
- Официальный репозиторий MySQL — свежая версия.
- Docker — изолированно, быстро.
Apt (Ubuntu)
Из репозитория ОС:
sudo apt update
sudo apt install mysql-server
sudo systemctl enable mysql
sudo systemctl start mysql
Версия в Ubuntu 22.04 — MySQL 8.0.
Официальный репозиторий
Для свежей версии:
wget https://dev.mysql.com/get/mysql-apt-config_0.8.32-1_all.deb
sudo dpkg -i mysql-apt-config_0.8.32-1_all.deb
sudo apt update
sudo apt install mysql-server
Что даёт: последняя стабильная версия.
Docker
Простой вариант:
docker run -d \
--name mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=myapp \
-e MYSQL_USER=app \
-e MYSQL_PASSWORD=secret \
-p 3306:3306 \
-v mysql_data:/var/lib/mysql \
mysql:8.0
Docker Compose:
services:
mysql:
image: mysql:8.0
command: --default-authentication-plugin=mysql_native_password
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: myapp
MYSQL_USER: app
MYSQL_PASSWORD: secret
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
volumes:
mysql_data:
⚠️ Обязательно volume, иначе данные пропадут при пересоздании контейнера.
Запуск и автозапуск
sudo systemctl status mysql
sudo systemctl start mysql
sudo systemctl enable mysql
sudo systemctl restart mysql
Логи:
sudo journalctl -u mysql -f
sudo tail -f /var/log/mysql/error.log
Первичная настройка
mysql_secure_installation:
sudo mysql_secure_installation
Интерактивно:
- Пароль root — установить.
caching_sha2_passwordvsmysql_native_password— обычно первое.- Удалить анонимных — да.
- Запретить root удалённо — да.
- Удалить тестовую БД — да.
- Перезагрузить таблицы привилегий — да.
Аутентификация
MySQL 8 по умолчанию: caching_sha2_password.
Проблема: старые клиенты (PHP < 7.4) не понимают.
Решение — для конкретного пользователя:
ALTER USER 'app'@'localhost'
IDENTIFIED WITH mysql_native_password BY 'secret';
Или в my.cnf:
[mysqld]
default_authentication_plugin = mysql_native_password
⚠️ mysql_native_password слабее, но совместимее.
Файлы конфигурации
Иерархия чтения:
/etc/my.cnf/etc/mysql/my.cnf/etc/mysql/conf.d/*.cnf/etc/mysql/mysql.conf.d/*.cnf
Последний прочитанный — приоритетный.
Основные параметры:
[mysqld]
user = mysql
bind-address = 127.0.0.1
port = 3306
# Кодировки
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
# Соединения
max_connections = 150
max_connect_errors = 1000
wait_timeout = 28800
interactive_timeout = 28800
# InnoDB
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 1
innodb_file_per_table = 1
# Логи
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_error = /var/log/mysql/error.log
innodb_buffer_pool_size
Самый важный параметр. Кеш страниц InnoDB.
Правило:
- На выделенном сервере — 70–80% RAM.
- На сервере с другими сервисами — 50%.
- Минимум — 128 MB.
Проверить:
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW STATUS LIKE 'Innodb_buffer_pool%';
Использование:
SELECT
ROUND(1 - (
(SELECT VARIABLE_VALUE FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Innodb_buffer_pool_pages_free') /
(SELECT VARIABLE_VALUE FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Innodb_buffer_pool_pages_total')
, 4) * 100 AS used_percent;
max_connections
По умолчанию: 151.
Проверить:
SHOW VARIABLES LIKE 'max_connections';
SHOW STATUS LIKE 'Max_used_connections';
Правило:
- max_used_connections ~ 80% от max_connections — увеличить.
- Приложению — пул соединений, не открывать на каждый запрос.
Ошибка:
ERROR 1040: Too many connections
wait_timeout
Через сколько секунд закрыть неактивное соединение.
По умолчанию: 28800 (8 часов).
Правило: для приложений — 300–600 секунд. Слишком долгий timeout — впустую держит соединения.
Логи
Виды:
- Error log — ошибки сервера.
- General query log — все запросы (для отладки).
- Slow query log — медленные.
- Binary log — для репликации и PITR.
Медленные запросы:
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = 1
Проверить:
SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';
Динамически:
SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 0.5;
Binlog
Для репликации и PITR:
log_bin = /var/log/mysql/mysql-bin.log
server_id = 1
binlog_format = ROW
binlog_row_image = minimal
expire_logs_days = 7
max_binlog_size = 512M
Проверить:
SHOW VARIABLES LIKE 'log_bin';
SHOW BINARY LOGS;
Очистить:
PURGE BINARY LOGS BEFORE NOW() - INTERVAL 7 DAY;
Удалённое подключение
В mysqld.cnf:
bind-address = 0.0.0.0 # слушать все интерфейсы
Пользователь с %:
CREATE USER 'app'@'%' IDENTIFIED BY 'secret';
GRANT ALL PRIVILEGES ON myapp.* TO 'app'@'%';
FLUSH PRIVILEGES;
Firewall:
sudo ufw allow from 10.0.0.0/8 to any port 3306
⚠️ Открывать 3306 в интернет — никогда. Только внутренняя сеть или SSH-туннель.
SSH-туннель
ssh -L 3307:localhost:3306 user@server
Теперь подключаетесь к 127.0.0.1:3307.
Проверка соединения
Сервер жив:
mysqladmin -h 127.0.0.1 -u app -p ping
# mysqld is alive
Проверка параметров:
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW VARIABLES LIKE 'max_connections';
SHOW VARIABLES LIKE 'character_set%';
Мониторинг
Активные соединения:
SHOW PROCESSLIST;
SELECT * FROM information_schema.processlist WHERE command != 'Sleep';
Статус:
SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW GLOBAL STATUS LIKE 'Queries';
SHOW GLOBAL STATUS LIKE 'Uptime';
SHOW GLOBAL STATUS LIKE 'Innodb_rows%';
Размер БД:
SELECT
table_schema,
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS mb
FROM information_schema.tables
WHERE table_schema = 'myapp'
GROUP BY table_schema;
Переменные: GLOBAL vs SESSION
GLOBAL — на весь сервер (нужен SUPER). SESSION — только для текущего соединения.
SET GLOBAL max_connections = 200;
SET SESSION sql_mode = 'STRICT_ALL_TABLES';
В my.cnf — применяется ко всем новым сессиям.
⚠️ SET GLOBAL не переживёт рестарт. Для персистентности — в конфиг.
Режим SQL (sql_mode)
Важно: влияет на строгость.
SELECT @@sql_mode;
Рекомендуемый:
sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
Что даёт:
STRICT_TRANS_TABLES— ошибка при вставке неверных данных.NO_ZERO_DATE— запрет0000-00-00.ERROR_FOR_DIVISION_BY_ZERO— ошибка при делении на 0.
⚠️ Без strict MySQL молча обрежет данные. С ним — ошибка.
Частые ошибки
1. Can't connect to local MySQL server through socket:
mysql не запущен или сокет в другом месте
Решение: systemctl start mysql, ps aux | grep mysqld.
2. Пароль root после установки:
В Ubuntu root без пароля, доступ через sudo
Решение: sudo mysql, затем ALTER USER.
3. Кончилось место:
Binlog растёт без ограничения
Решение: expire_logs_days = 7.
4. Медленные запросы без slow-лога:
Непонятно, что тормозит
Решение: включить slow_query_log.
5. Кодировка в контейнере:
Все таблицы в latin1
Решение: указать --character-set-server=utf8mb4.
6. Пул соединений на стороне клиента:
Каждый запрос открывает новое соединение
Решение: pool на приложении (HikariCP, mysql2 pool, Laravel PDO).
7. Тюнинг без мониторинга:
Изменили innodb_buffer_pool_size без замеров
Решение: сначала baseline, потом менять.
Практика
1. Установите MySQL 8 или MariaDB.
2. Настройте my.cnf:
character-set-server = utf8mb4
max_connections = 200
innodb_buffer_pool_size = 512M
slow_query_log = 1
long_query_time = 1
3. Перезапустите, проверьте параметры.
4. Создайте пользователя, подключитесь по TCP.
5. Сделайте медленный запрос (с SLEEP(3)), проверьте slow-лог.
6. Посмотрите SHOW PROCESSLIST, SHOW STATUS.
Итог
- Установка: apt, Docker, официальный репо.
- Кодировка:
utf8mb4. innodb_buffer_pool_size— главный параметр.max_connections— под нагрузку, но лучше пул.- Logs: slow, error, binlog.
sql_mode— строгий.- Удалённо — только через SSH-туннель.
Дальше — типы данных MySQL.