Menu
Hosting Domeny VPS SSL Kalkulator Porównania FAQ
Aktywne kody
Wszystkie kody rabatowe

MySQLTuner - optymalizacja MySQL i MariaDB na VPS

Opublikowano: 10 kwietnia 2026 · Kategoria: VPS / Bazy danych

Domyślna konfiguracja MySQL jest celowo ostrożna - zaprojektowana do działania na serwerach z minimalną pamięcią i nie wykorzystuje zasobów, które masz na VPS. Wynikiem są wolne zapytania, zbyt mało połączeń i nadmierne odczyty z dysku zamiast z RAM. MySQLTuner to narzędzie, które analizuje Twój serwer i mówi wprost co zmienić i dlaczego. Artykuł pokazuje jak interpretować raport i implementować rekomendacje.

Pobranie i uruchomienie MySQLTuner

# Pobierz najnowszą wersję MySQLTuner
wget http://mysqltuner.pl/ -O mysqltuner.pl
wget https://raw.githubusercontent.com/major/MySQLTuner-perl/master/basic_passwords.txt -O basic_passwords.txt
wget https://raw.githubusercontent.com/major/MySQLTuner-perl/master/vulnerabilities.csv -O vulnerabilities.csv

# Uruchomienie (jako root lub uzytkownik z pelnym dostepem)
perl mysqltuner.pl --user root --pass "TwojHaslo"

# Lub z pliku .my.cnf (bezpieczniejsze)
# [client]
# user=root
# password=TwojHaslo
# plik: ~/.my.cnf (chmod 600)
perl mysqltuner.pl

# Opcje zaawansowane
perl mysqltuner.pl \
  --buffers        \  # szczegoly buforow
  --idxstats       \  # statystyki indeksow
  --dbstat         \  # statystyki baz
  --outputfile /tmp/mysqltuner-report.txt   # zapis do pliku

Instalacja MySQLTuner z repozytorium pakietów lub z GitHuba

MySQLTuner to pojedynczy skrypt Perl, więc nie trzeba go instalować: wystarczy pobrać plik mysqltuner.pl jak wyżej. Jeśli wolisz mieć go jako pakiet systemowy (aktualizacje razem z resztą systemu), jest dostępny w repozytoriach Debiana i Ubuntu oraz w EPEL dla AlmaLinux i Rocky Linux. Wersja z repozytorium bywa starsza niż ta z GitHuba, a starsze wersje gorzej rozpoznają nowe wydania MySQL i MariaDB, dlatego przy nowym serwerze bazy lepiej uruchomić najnowszy skrypt.

# Debian / Ubuntu
sudo apt update && sudo apt install mysqltuner
sudo mysqltuner

# AlmaLinux / Rocky Linux (repozytorium EPEL)
sudo dnf install epel-release
sudo dnf install mysqltuner

# Najnowsza wersja prosto z GitHuba (MySQLTuner download)
git clone --depth 1 https://github.com/major/MySQLTuner-perl.git
cd MySQLTuner-perl
perl mysqltuner.pl --user root --pass "TwojHaslo"

# Wymagania: interpreter Perl (jest w praktycznie każdej dystrybucji Linuksa)
perl -v

MySQLTuner online, w Dockerze i na Windowsie

MySQLTuner online. Oficjalny projekt nie ma wersji online. Skrypt musi połączyć się z serwerem bazy i odczytać jego zmienne oraz liczniki, więc uruchamiasz go na serwerze albo na maszynie, która ma dostęp do bazy przez sieć. Serwisy "online", do których wkleja się wynik SHOW GLOBAL STATUS i SHOW GLOBAL VARIABLES, dostają pełny obraz konfiguracji Twojej bazy, dlatego na produkcji bezpieczniej użyć lokalnego skryptu.

Połączenie zdalne. Gdy uruchamiasz MySQLTuner na innej maszynie niż baza, skrypt nie widzi pamięci RAM ani swapu serwera bazy. Trzeba je podać ręcznie przez --forcemem i --forceswap (w MB), inaczej rekomendacje dotyczące buforów będą policzone dla złej maszyny.

MySQLTuner w Dockerze. Najprostsza droga to uruchomienie skryptu na hoście i połączenie z kontenerem przez opublikowany port. Jako --forcemem podaj limit pamięci kontenera (a nie RAM całego hosta), bo to on wyznacza, ile może zająć bufor InnoDB. Użyj adresu 127.0.0.1, a nie localhost: klient MySQL przy localhost próbuje połączyć się przez gniazdo uniksowe, którego na hoście nie ma.

# Baza na innym serwerze (VPS 4 GB RAM, 1 GB swap)
perl mysqltuner.pl --host 10.0.0.5 --port 3306 \
  --user tuner --pass "TwojHaslo" \
  --forcemem 4096 --forceswap 1024

# Baza w kontenerze z portem 3306 opublikowanym na hoście
docker inspect --format '{{.HostConfig.Memory}}' nazwa_kontenera   # limit w bajtach, 0 = brak limitu
perl mysqltuner.pl --host 127.0.0.1 --port 3306 \
  --user root --pass "TwojHaslo" --forcemem 2048

MySQLTuner na Windowsie. Skrypt jest pisany pod Linuksa i Uniksa (część danych o systemie czyta z narzędzi systemowych), więc na Windowsie najwygodniej uruchomić go w WSL albo z dowolnej maszyny z Linuksem, łącząc się z bazą zdalnie z parametrem --forcemem.

Interpretacja raportu - sekcje wyjścia

MySQLTuner dzieli raport na sekcje. Kluczowe linie to te z [!!] (ostrzeżenie) i [OK] (w porządku). Na końcu sekcja Recommendations zbiera konkretne zmiany do zastosowania.

-------- General Statistics --------
[--] Skipped version check for MySQLTuner script
[OK]  Currently running supported MySQL version 8.0.36-MySQL

-------- Storage Engine Statistics --------
[OK]  InnoDB is enabled
[!!]  InnoDB buffer pool / data size: 128.0M/4.5G       # KLUCZOWE!
[!!]  InnoDB buffer pool instances: 1 (recommended: 4+)
[OK]  InnoDB Read buffer efficiency: 94.28%              # powinno byc >99%

-------- Performance Metrics --------
[!!]  Slow queries: 2% (1K/52K)                         # powyzej 1% = problem
[OK]  Highest connection usage: 42% of max_connections
[!!]  Threads created per second: 12 (should be < 5)    # thread cache za maly
[OK]  Table cache hit rate: 91%

-------- Recommendations --------
General recommendations:
  Add skip-name-resolve to my.cnf
  innodb_buffer_pool_size (>= 3G)
  innodb_buffer_pool_instances = 4
  thread_cache_size = 50
  slow_query_log = 1

Najczęstsze ostrzeżenia [!!] i co z nimi zrobić

Ostrzeżenie w raporcie Co oznacza Co zrobić
Maximum possible memory usage Przy komplecie połączeń bufory per połączenie mogą przekroczyć RAM Obniż max_connections do realnego szczytu albo zmniejsz bufory per połączenie (sort_buffer_size, join_buffer_size)
Joins performed without indexes Zapytania łączą tabele bez indeksu na kolumnie złączenia Znajdź je w slow query log i dodaj indeksy; podnoszenie join_buffer_size tylko maskuje problem
Temporary tables created on disk Tabele tymczasowe nie mieszczą się w pamięci Podnieś razem tmp_table_size i max_heap_table_size; kolumny TEXT/BLOB w wyniku i tak trafią na dysk, wtedy pomaga zmiana zapytania
Key buffer used / MyISAM Część tabel nadal używa silnika MyISAM Zamień tabele na InnoDB (ALTER TABLE ... ENGINE=InnoDB, po kopii zapasowej), wtedy key_buffer_size można zmniejszyć
Aborted connections Klienci zrywają połączenia albo podają złe hasło Sprawdź log błędów, timeouty aplikacji i próby logowania z zewnątrz; baza nie powinna nasłuchiwać publicznie
Name resolution is active Każde połączenie wymaga odpytania DNS Dodaj skip-name-resolve i nadawaj uprawnienia po adresach IP, nie nazwach hostów

Kluczowe parametry i ich optymalizacja

Parametr Domyślna wartość Rekomendacja (VPS 8 GB) Efekt
innodb_buffer_pool_size 128 MB 4-6 GB (70% RAM) Więcej danych w RAM, mniej I/O dysku
innodb_buffer_pool_instances 1 4-8 (1 per GB pool) Mniejszy contention na mutex pool
max_connections 151 300-500 Więcej równoczesnych połączeń
thread_cache_size 9 50-100 Mniej tworzenia nowych wątków (CPU)
query_cache_type 0 (OFF) w MySQL 5.7 i MariaDB 10.1.7+ 0 (OFF, read-heavy: 1) Brak mutex contention przy write-heavy
innodb_log_file_size 48 MB 256-512 MB Mniej checkpoint flushes, lepszy write perf
tmp_table_size / max_heap_table_size 16 MB 64-256 MB Mniej temporary tables na dysku
# /etc/mysql/mysql.conf.d/mysqld.cnf - przykład dla VPS 8 GB RAM

# [mysqld]
# --- InnoDB ---
# innodb_buffer_pool_size = 4G
# innodb_buffer_pool_instances = 4
# innodb_log_file_size = 256M
# innodb_flush_log_at_trx_commit = 2    # 1=bezpieczne, 2=szybsze (ryzyko utraty 1s transakcji)
# innodb_flush_method = O_DIRECT
#
# --- Polaczenia ---
# max_connections = 300
# thread_cache_size = 50
# wait_timeout = 300
# interactive_timeout = 300
#
# --- Tymczasowe tabele ---
# tmp_table_size = 128M
# max_heap_table_size = 128M
#
# --- Query cache (MySQL 5.7 - dla MySQL 8.0 usun) ---
# query_cache_type = 0
# query_cache_size = 0
#
# --- Slow query log ---
# slow_query_log = 1
# slow_query_log_file = /var/log/mysql/slow.log
# long_query_time = 1
# log_queries_not_using_indexes = 1
#
# --- Siec ---
# skip-name-resolve
# bind-address = 127.0.0.1

# Zastosuj bez restartu (czesciowo)
mysql -u root -p -e "SET GLOBAL innodb_buffer_pool_size = 4*1024*1024*1024;"
mysql -u root -p -e "SET GLOBAL max_connections = 300;"

# Pelny restart (dla innodb_log_file_size wymagany)
sudo systemctl restart mysql

Nowsze wersje: MySQL 8.0.30+ i MariaDB 10.5+

Część parametrów z przykładu wyżej zmieniła się w nowszych wydaniach i stara konfiguracja przeniesiona 1:1 może dać ostrzeżenia w logu albo zostać po cichu zignorowana:

  • MySQL 8.0.30 i nowsze: rozmiar dziennika redo ustawia innodb_redo_log_capacity, a innodb_log_file_size i innodb_log_files_in_group są przestarzałe. Na nowej instalacji ustawiaj jeden parametr, np. innodb_redo_log_capacity = 512M.
  • MySQL 8.0: query cache nie istnieje, więc wpisy query_cache_* w my.cnf powodują błąd startu serwera. Usuń je przed aktualizacją z 5.7.
  • MariaDB 10.5 i nowsze: InnoDB używa jednej instancji puli buforów, a innodb_buffer_pool_instances jest przestarzały (w 10.6 usunięty), więc rekomendacja "4+ instancje" ze starszych wersji MySQLTuner nie ma tu zastosowania.

SHOW VARIABLES vs SHOW STATUS - diagnostyka

# SHOW VARIABLES - aktualna konfiguracja
SHOW GLOBAL VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW GLOBAL VARIABLES LIKE 'max_connections';
SHOW GLOBAL VARIABLES LIKE '%cache%';

# SHOW STATUS - statystyki runtime (od ostatniego restartu)
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';
-- Innodb_buffer_pool_read_requests  = total reads tried from buffer
-- Innodb_buffer_pool_reads          = reads that needed disk I/O
-- Ratio hit: 1 - (Reads / Read_requests) powinno byc >99%

SHOW GLOBAL STATUS LIKE 'Threads%';
-- Threads_created    = ile watkow bylo tworzonych (powinno byc niskie)
-- Threads_running    = aktualnie aktywne watki

SHOW GLOBAL STATUS LIKE 'Slow_queries';
SHOW GLOBAL STATUS LIKE 'Questions';   -- total queries

SHOW GLOBAL STATUS LIKE 'Qcache%';
-- Qcache_hits / (Qcache_hits + Qcache_inserts) = skutecznosc query cache

-- Uzyteczne widoki diagnostyczne (MySQL 8.0+ / MariaDB)
SELECT * FROM sys.statement_analysis LIMIT 10;        -- top slow queries
SELECT * FROM sys.user_summary;                       -- aktywnosc per user
SELECT * FROM information_schema.INNODB_BUFFER_POOL_STATS;

Weryfikacja po zmianach

# Zresetuj statystyki statusu
FLUSH STATUS;

# Poczekaj 24h, potem sprawdz skutecznosc bufora
SELECT
  (1 - (
    variable_value / (
      SELECT variable_value
      FROM information_schema.GLOBAL_STATUS
      WHERE variable_name = 'Innodb_buffer_pool_read_requests'
    )
  )) * 100 AS buffer_hit_ratio_pct
FROM information_schema.GLOBAL_STATUS
WHERE variable_name = 'Innodb_buffer_pool_reads';
-- Cel: > 99%

# Uruchom MySQLTuner po 24-48h i porownaj z poprzednim raportem
perl mysqltuner.pl >> /tmp/after-tuning.txt

# Sprawdz slow query log
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
# -s t  = sortuj po query_time
# -t 10 = top 10

Jak bezpiecznie stosować rekomendacje MySQLTuner

MySQLTuner liczy rekomendacje z liczników od ostatniego restartu i nie zna Twojej aplikacji. Dlatego jego wynik to lista hipotez do sprawdzenia, a nie gotowy my.cnf. Kilka zasad, które oszczędzają nocnych restartów:

  • Uruchamiaj po co najmniej 24 h normalnego ruchu. Raport zaraz po restarcie bazy opiera się na kilku minutach statystyk i potrafi zalecić odwrotne zmiany niż raport z pełnej doby.
  • Zmieniaj jeden parametr naraz. Po zmianie odczekaj kolejną dobę i porównaj raporty (--outputfile z datą w nazwie). Przy kilku zmianach jednocześnie nie wiadomo, która pomogła, a która zaszkodziła.
  • Pilnuj sumy pamięci. Bufory per połączenie mnożą się przez liczbę połączeń. Podniesienie max_connections i sort_buffer_size naraz może przy szczycie ruchu skończyć się zabiciem procesu bazy przez OOM killer.
  • Zrób kopię my.cnf przed edycją i sprawdź składnię przed restartem (mysqld --validate-config w MySQL 8.0.16+), żeby literówka nie zatrzymała bazy.
  • Na hostingu współdzielonym nie dostosujesz serwera. Konfigurację MySQL ustawia tam dostawca. MySQLTuner ma sens na własnym VPS lub serwerze dedykowanym; na współdzielonym zostaje optymalizacja zapytań i indeksów.

Gotowe ustawienia my.cnf dla VPS 2 GB i 4 GB RAM (innodb_buffer_pool_size, max_connections, tmp_table_size) znajdziesz w artykule MySQL - optymalizacja i konfiguracja my.cnf.

Najczęstsze pytania

Co to jest MySQLTuner i jak go uruchomić? +
MySQLTuner to skrypt Perl analizujący konfigurację i statystyki runtime MySQL/MariaDB. Pobiera dane z SHOW VARIABLES i SHOW STATUS, porównuje z best practices i generuje listę rekomendacji z priorytetami. Uruchamiasz go: wget http://mysqltuner.pl/ -O mysqltuner.pl && perl mysqltuner.pl --user root --pass HASLO. Zalecane uruchamianie po minimum 24 godzinach działania serwera - wtedy statystyki są reprezentatywne. Nie wymaga instalacji, działa na żywym serwerze.
Jak dobrać wartość innodb_buffer_pool_size? +
innodb_buffer_pool_size to najważniejszy parametr InnoDB - im większy, tym więcej danych trzymanych w RAM zamiast czytanych z dysku. Reguła: dla dedykowanego serwera MySQL ustaw 70-80% dostępnego RAM. Dla shared hostingu (MySQL współdzieli serwer z Apache/PHP) - 25-50%. Sprawdź: SHOW GLOBAL STATUS LIKE "Innodb_buffer_pool_read_requests" i "Innodb_buffer_pool_reads" - ratio powinien wynosić ponad 99% (mniej niż 1% trafień wymaga dysku).
Czym różni się SHOW VARIABLES od SHOW STATUS? +
SHOW VARIABLES pokazuje bieżącą konfigurację - wartości parametrów z my.cnf (innodb_buffer_pool_size, max_connections, query_cache_size). Są statyczne lub semi-statyczne (część można zmienić przez SET GLOBAL). SHOW STATUS pokazuje statystyki runtime - liczniki od ostatniego restartu (Connections, Queries, Threads_running, Innodb_buffer_pool_reads). Łącząc oba otrzymujesz pełny obraz: konfigurację + efektywność jej działania.
Kiedy wyłączyć query_cache w MySQL? +
Query cache (query_cache_type) warto wyłączyć gdy masz dużo zapisów (INSERT/UPDATE/DELETE) - każdy zapis do tabeli unieważnia wszystkie zapytania dla tej tabeli w cache, generując mutex contention. Dla write-heavy baz query cache pogarsza wydajność. MySQL 8.0 całkowicie usunął query cache. Dla MariaDB: ustaw query_cache_type=0 query_cache_size=0 jeśli Qcache_lowmem_prunes jest wysokie lub Qcache_hits / (Qcache_hits + Qcache_inserts) jest poniżej 20%.
Czy jest MySQLTuner online? +
Oficjalny MySQLTuner nie ma wersji online. To skrypt Perl, który musi połączyć się z bazą, więc uruchamiasz go na serwerze albo na maszynie z dostępem sieciowym do bazy (parametry --host i --port, a RAM serwera bazy podajesz przez --forcemem w MB). Wklejanie wyników SHOW GLOBAL STATUS i SHOW GLOBAL VARIABLES do zewnętrznych serwisów ujawnia konfigurację bazy, dlatego na produkcji lepiej użyć lokalnego skryptu.
Skąd pobrać MySQLTuner? +
Najnowszą wersję pobierzesz z GitHuba projektu (git clone https://github.com/major/MySQLTuner-perl.git) albo jednym poleceniem: wget http://mysqltuner.pl/ -O mysqltuner.pl. Jest też pakiet mysqltuner w repozytoriach Debiana i Ubuntu (apt install mysqltuner) oraz w EPEL dla AlmaLinux i Rocky Linux. Wersja z repozytorium bywa starsza, więc dla nowych wydań MySQL i MariaDB lepiej użyć skryptu z GitHuba.
Jak uruchomić MySQLTuner dla bazy w Dockerze? +
Uruchom skrypt na hoście i połącz się z kontenerem przez opublikowany port: perl mysqltuner.pl --host 127.0.0.1 --port 3306 --user root --pass HASLO --forcemem 2048. Jako --forcemem podaj limit pamięci kontenera w MB, a nie RAM całego hosta. Adres 127.0.0.1 zamiast localhost wymusza połączenie TCP, bo localhost oznacza dla klienta MySQL gniazdo uniksowe.

Sprawdź oferty pasujące do tego scenariusza

Poniżej masz szybkie przejścia do ofert i stron z kodami rabatowymi tam, gdzie są dostępne.