MySQL 8.x’den MariaDB 11.x ve 12.x’e Veritabanı Aktarımı ve Dikkat Edilmesi Gereken Konular
Bir gün patronunuz gelir ve “MySQL lisansı artık çok pahalı, MariaDB’ye geçiyoruz” der. Ya da siz kendiniz fark edersiniz: MySQL 8.x’in bazı davranışları projenizle uyumsuz, MariaDB 11.x çok daha iyi özellikler sunuyor. Her iki durumda da karşınızda ciddi bir migration süreci var demektir. Bu yazıda MySQL 8.x’ten MariaDB 11.x/12.x’e geçiş sürecini, kendi ellerimle yaptığım aktarımlardan öğrendiklerimi aktararak detaylıca anlatacağım. Bazı şeyler belgelerde yazmaz, deneyerek öğrenirsiniz.
Neden Bu Geçiş Kolay Değil?
MariaDB, MySQL’in bir fork’u olarak başladı ve uzun süre “MySQL uyumlu” olduğunu iddia etti. Küçük sürümler arasında bu büyük ölçüde doğruydu. Ancak MySQL 8.0 ile Oracle ciddi değişiklikler yaptı ve MariaDB kendi yoluna daha kararlı biçimde girdi. Sonuç olarak MySQL 8.x ile MariaDB 10.6+ arasında görünürde uyumluluk var gibi görünse de, altta pek çok farklılık mevcut.
MariaDB 11.x serisine gelindiğinde bu farklılıklar daha da belirginleşiyor. Authentication plugin sistemi, JSON desteğinin implementasyonu, information_schema yapısı, sistem tabloları ve hatta bazı SQL sözdizimi farklılıkları migration sırasında sizi bekliyor. Bunları bilmeden yapılan geçişler genellikle “her şey çalışıyor gibi görünüyor ama 2 hafta sonra uygulama garip hatalar veriyor” senaryosuyla sonuçlanır.
Ortam Analizi: Atlamayın, Pişman Olursunuz
Geçişe başlamadan önce mevcut MySQL kurulumunuzu iyice tanımanız gerekiyor. “Nasılsa mysqldump alırım, import ederim” düşüncesi çok riskli.
MySQL sürümünüzü ve motor bilgilerini öğrenin:
mysql -u root -p -e "SELECT VERSION();"
mysql -u root -p -e "SHOW ENGINES;"
mysql -u root -p -e "SHOW VARIABLES LIKE 'innodb_file_format';"
mysql -u root -p -e "SHOW VARIABLES LIKE 'sql_mode';"
Hangi character set ve collation kullandığınızı tespit edin:
mysql -u root -p -e "
SELECT
SCHEMA_NAME,
DEFAULT_CHARACTER_SET_NAME,
DEFAULT_COLLATION_NAME
FROM information_schema.SCHEMATA
WHERE SCHEMA_NAME NOT IN ('mysql','information_schema','performance_schema','sys');
"
Bu sorgu size çok şey söyler. Eğer utf8mb4_0900_ai_ci collation kullanıyorsanız, MariaDB 11.x’te bu collation varsayılan olarak aynı şekilde davranmaz. MariaDB kendi utf8mb4_uca1400_ai_ci collation’ını getirdi ve utf8mb4_0900_ai_ci‘yi tam olarak desteklemez. Bu fark, özellikle Türkçe karakter sıralamasında ciddi sorunlara yol açabilir.
Stored procedure, function ve trigger envanteri çıkarın:
mysql -u root -p information_schema -e "
SELECT ROUTINE_SCHEMA, ROUTINE_NAME, ROUTINE_TYPE
FROM ROUTINES
WHERE ROUTINE_SCHEMA NOT IN ('mysql','information_schema','performance_schema','sys');
"
mysql -u root -p information_schema -e "
SELECT TRIGGER_SCHEMA, TRIGGER_NAME, EVENT_MANIPULATION, EVENT_OBJECT_TABLE
FROM TRIGGERS
WHERE TRIGGER_SCHEMA NOT IN ('mysql','information_schema','performance_schema','sys');
"
Stored procedure ve function’larınız varsa bunları ayrıca incelemeniz gerekiyor. MySQL 8.x’e özgü bazı fonksiyonlar MariaDB’de ya yok ya da farklı çalışıyor. JSON_TABLE() fonksiyonunun davranışı, LAG() ve LEAD() window function’larının bazı edge case’leri, REGEXP_REPLACE() parametreleri bunların başında geliyor.
Yedek Alma Stratejisi
Mysqldump ile yedek alırken kullandığınız parametreler, migration’ın başarısını doğrudan etkiliyor. Standart bir mysqldump almak yetmez.
Temel migration dump:
mysqldump
--user=root
--password
--host=localhost
--single-transaction
--routines
--triggers
--events
--add-drop-database
--databases veritabani1 veritabani2
--set-gtid-purged=OFF
--column-statistics=0
> /backup/mysql8_full_dump_$(date +%Y%m%d_%H%M%S).sql
Burada dikkat edilmesi gereken birkaç parametre var:
- –single-transaction: InnoDB tablolar için consistent snapshot alır, tabloları kilitlemez. Üretim ortamında şart.
- –set-gtid-purged=OFF: MySQL 8.x GTID replikasyonu kullanıyorsa bu bayrak olmadan alınan dump, MariaDB’ye import edilemez. MariaDB GTID yapısı farklı.
- –column-statistics=0: MySQL 8.x’in mysqldump’ı varsayılan olarak column statistics bilgisi eklemeye çalışır. MariaDB’de bu tablo yok, hata alırsınız.
- –routines: Stored procedure ve function’ları dahil eder.
- –events: Scheduled event’leri dahil eder.
Büyük veritabanları için parçalı yedek:
Terabayt mertebesinde veritabanlarında tek dump dosyası yönetimi zorlaşır. Bu durumda mydumper kullanmak çok daha mantıklı:
# mydumper kurulumu (Ubuntu/Debian)
apt-get install mydumper
# Parçalı dump alma
mydumper
--user=root
--password=SifreNiz
--host=localhost
--outputdir=/backup/mydumper_output
--rows=500000
--compress
--build-empty-files
--threads=4
--trx-consistency-only
--verbose=3
Dump Dosyasının Temizlenmesi
İşte çoğu dokümanda atlanan kritik adım bu. MySQL 8.x’ten alınan dump dosyası, MariaDB’ye direkt import edilemeyecek bazı öğeler içeriyor. Bunları elle veya script ile temizlemeniz gerekiyor.
Sorunlu kısımları tespit edin:
# utf8mb4_0900_ai_ci collation kullanımını tespit et
grep -c "utf8mb4_0900_ai_ci" /backup/mysql8_full_dump.sql
# MySQL'e özgü SET ifadelerini bul
grep "SET @MYSQLDUMP_TEMP_LOG_BIN" /backup/mysql8_full_dump.sql
grep "SET @@SESSION.SQL_LOG_BIN" /backup/mysql8_full_dump.sql
# Sorunlu DEFINER ifadelerini kontrol et
grep "DEFINER=" /backup/mysql8_full_dump.sql | head -20
Collation dönüşümü:
# utf8mb4_0900_ai_ci'yi MariaDB uyumlu collation ile değiştir
sed -i 's/utf8mb4_0900_ai_ci/utf8mb4_general_ci/g' /backup/mysql8_full_dump.sql
# utf8mb4_0900_as_cs (case sensitive) için
sed -i 's/utf8mb4_0900_as_cs/utf8mb4_bin/g' /backup/mysql8_full_dump.sql
# MySQL 8.x'e özgü SET ifadelerini kaldır
sed -i '/SET @MYSQLDUMP_TEMP_LOG_BIN/d' /backup/mysql8_full_dump.sql
sed -i '/SET @@SESSION.SQL_LOG_BIN/d' /backup/mysql8_full_dump.sql
Burada utf8mb4_general_ci mi yoksa MariaDB 11.x’in kendi utf8mb4_uca1400_ai_ci‘sini mi kullanacağınız önemli bir karar. Eğer Türkçe karakter sıralaması kritikse, utf8mb4_unicode_ci‘yi tercih etmenizi öneririm. Hem MySQL hem MariaDB’de tutarlı davranır.
NO_ZERO_DATE ve sql_mode sorunları:
MySQL 8.x ile MariaDB’nin sql_mode varsayılanları farklı. Bazı uygulamalar MySQL’de 0000-00-00 tarih değerleri kullanıyor olabilir. Bunlar MariaDB’de hata verebilir.
# Dump dosyasının başına MariaDB uyumlu sql_mode ekle
sed -i '1s/^/SET sql_mode="NO_AUTO_VALUE_ON_ZERO,NO_ENGINE_SUBSTITUTION";nn/' /backup/mysql8_full_dump.sql
MariaDB 11.x Kurulumu
MariaDB’nin kendi resmi repository’sini kullanmanızı şiddetle tavsiye ederim. Dağıtım paket depolarındaki sürümler genellikle eski kalıyor.
Ubuntu 22.04/24.04 üzerinde MariaDB 11.x kurulumu:
# Önce sistemi temizle, eski MySQL paketlerini kaldır
apt-get remove --purge mysql-server mysql-client mysql-common
apt-get autoremove
apt-get autoclean
# MariaDB Foundation repository kurulumu
curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup |
bash -s -- --mariadb-server-version="mariadb-11.4"
# Kurulum
apt-get update
apt-get install mariadb-server mariadb-client
# Servis kontrolü
systemctl enable mariadb
systemctl start mariadb
systemctl status mariadb
# Güvenlik yapılandırması
mariadb-secure-installation
MariaDB 11.x için temel my.cnf yapılandırması:
[mysqld]
# Temel ayarlar
datadir=/var/lib/mysql
socket=/var/run/mysqld/mysqld.sock
pid-file=/var/run/mysqld/mysqld.pid
# Karakter seti - migration öncesi belirleyin
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
# InnoDB ayarları
innodb_buffer_pool_size=4G
innodb_log_file_size=512M
innodb_flush_log_at_trx_commit=1
innodb_file_per_table=ON
# Bağlantı ayarları
max_connections=500
wait_timeout=600
interactive_timeout=600
# Geçiş sürecinde yararlı
sql_mode=NO_AUTO_VALUE_ON_ZERO,NO_ENGINE_SUBSTITUTION
# Binary log (replikasyon için)
log_bin=/var/log/mysql/mariadb-bin
binlog_format=ROW
expire_logs_days=7
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
collation-server=utf8mb4_unicode_ci ayarını dikkat edin. Burada utf8mb4_0900_ai_ci yazmayın. MariaDB 11.x bu collation’ı tanır ama MySQL’deki tam implementasyonu yoktur ve beklenmedik sıralama farklılıkları yaratır.
Import Süreci
Dump dosyası hazır, MariaDB kurulu. Şimdi import zamanı. Büyük veritabanlarında bu süreç saatler alabilir, birkaç optimizasyon önemli.
Import öncesi MariaDB performans optimizasyonu:
# Import sırasında geçici olarak bazı kontrolleri devre dışı bırak
mysql -u root -p -e "
SET GLOBAL innodb_flush_log_at_trx_commit=0;
SET GLOBAL innodb_doublewrite=0;
SET GLOBAL sync_binlog=0;
"
Import işlemi:
# Büyük dosyalar için pv ile ilerleme takibi
apt-get install pv
pv /backup/mysql8_full_dump_cleaned.sql | mysql -u root -p --max_allowed_packet=512M
# Ya da doğrudan mysql ile
mysql -u root -p
--max_allowed_packet=512M
--net_buffer_length=16384
< /backup/mysql8_full_dump_cleaned.sql
Import sonrası ayarları geri al:
mysql -u root -p -e "
SET GLOBAL innodb_flush_log_at_trx_commit=1;
SET GLOBAL innodb_doublewrite=ON;
SET GLOBAL sync_binlog=1;
"
Kritik Farklılıklar ve Çözümleri
Authentication Plugin Değişikliği
MySQL 8.x varsayılan authentication plugin’i caching_sha2_password‘dur. MariaDB bunu desteklemez ve kendi mysql_native_password ve ed25519 plugin’lerini kullanır. Uygulama kullanıcılarınız için bunu kontrol edin.
# MySQL'deki kullanıcı authentication bilgisi
mysql -u root -p -e "
SELECT User, Host, plugin
FROM mysql.user
WHERE User NOT IN ('root','mysql.sys','mysql.session','mysql.infoschema');
"
# MariaDB'de kullanıcı oluşturma
mariadb -u root -p -e "
CREATE USER 'app_user'@'%' IDENTIFIED VIA mysql_native_password USING PASSWORD('SifreNiz');
GRANT ALL PRIVILEGES ON uygulama_db.* TO 'app_user'@'%';
FLUSH PRIVILEGES;
"
Eğer dump dosyanızda caching_sha2_password ile oluşturulmuş kullanıcılar varsa, bunları MariaDB’de yeniden oluşturmanız gerekecek.
JSON Sütunları
MySQL 8.x’te JSON tipi binary format’ta saklanır ve gelişmiş JSON fonksiyonları sunar. MariaDB 10.2’den itibaren JSON desteği var ama bazı fonksiyonlar farklı çalışıyor. MariaDB 11.x ile fark kapanmış olsa da dikkat edilmesi gereken noktalar var:
JSON_TABLE()MariaDB 10.6+ ile geldi, syntax farklılıkları olabilir.JSON_ARRAYAGG()veJSON_OBJECTAGG()davranışı bazı edge case’lerde farklı.->ve->>operatörleri MariaDB 10.2.3+ destekler.
Uygulamanızda yoğun JSON sorguları varsa bunları ayrıca test edin.
Generated Columns (Hesaplanmış Sütunlar)
# MySQL 8.x'te STORED ve VIRTUAL generated columns her ikisi de desteklenir
# MariaDB'de syntax biraz farklı, dump'tan gelen ifadeler sorun çıkarabilir
# Sorunlu generated column ifadelerini tespit et
grep -i "GENERATED ALWAYS AS" /backup/mysql8_full_dump_cleaned.sql
MariaDB 11.x GENERATED ALWAYS AS syntax’ını destekler ama bazı expression farklılıkları olabilir. Özellikle JSON fonksiyonu kullanan generated column’lar kontrol edilmeli.
CHECK Constraints
MySQL 8.0.16 öncesinde CHECK constraints parse edilir ama enforce edilmezdi. MySQL 8.0.16+ artık enforced. MariaDB 10.2.1’den beri enforced. Bu fark, MySQL 8.x’in eski sürümlerinden yapılan dump’larda sorun çıkarabilir.
Doğrulama Adımları
Import tamamlandı. Şimdi en kritik adım: verinin doğru geldiğini teyit etmek.
Tablo ve satır sayısı karşılaştırması:
# MySQL 8.x'te çalıştırın
mysql -u root -p -e "
SELECT
TABLE_SCHEMA,
COUNT(*) as tablo_sayisi,
SUM(TABLE_ROWS) as toplam_satir_tahmini
FROM information_schema.TABLES
WHERE TABLE_SCHEMA NOT IN ('mysql','information_schema','performance_schema','sys')
AND TABLE_TYPE='BASE TABLE'
GROUP BY TABLE_SCHEMA;
"
# MariaDB 11.x'te çalıştırın
mariadb -u root -p -e "
SELECT
TABLE_SCHEMA,
COUNT(*) as tablo_sayisi,
SUM(TABLE_ROWS) as toplam_satir_tahmini
FROM information_schema.TABLES
WHERE TABLE_SCHEMA NOT IN ('mysql','information_schema','performance_schema','sys')
AND TABLE_TYPE='BASE TABLE'
GROUP BY TABLE_SCHEMA;
"
TABLE_ROWS değeri InnoDB için tahmini bir değer olduğunu unutmayın. Kritik tablolar için gerçek COUNT(*) yapın.
Index ve constraint kontrolü:
mariadb -u root -p -e "
SELECT
TABLE_SCHEMA,
TABLE_NAME,
INDEX_NAME,
COLUMN_NAME,
NON_UNIQUE
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA NOT IN ('mysql','information_schema','performance_schema','sys')
ORDER BY TABLE_SCHEMA, TABLE_NAME, INDEX_NAME;
" > /tmp/mariadb_indexes.txt
# MySQL çıktısıyla karşılaştır
diff /tmp/mysql_indexes.txt /tmp/mariadb_indexes.txt
Uygulama Tarafında Yapılması Gerekenler
Veritabanı tarafı hazır ama işin bitmedi. Uygulama connection string’lerini ve driver’larını da güncellemeniz gerekebilir.
PHP PDO bağlantısı genellikle sorunsuz çalışır, MariaDB MySQL protokolünü kullanır. Ama charset=utf8mb4 olduğundan emin olun.
Java JDBC için MySQL Connector/J kullanıyorsanız MariaDB Connector/J’ye geçmeyi düşünün. Bazı MySQL 8.x özelliklerine dayanan kodlar sorun çıkarabilir.
Python mysql-connector veya PyMySQL kullananlar genellikle sorunsuz geçer. authentication_plugin='mysql_native_password' parametresini bağlantıya eklemek bazen gerekebilir.
Node.js mysql2 paketi MariaDB ile uyumlu çalışır. authPlugins yapılandırmasına dikkat edin.
Uygulamanızın MariaDB ile çalıştığını teyit etmek için önce staging ortamında geçiş yapın ve yük testleri çalıştırın. Özellikle sorgu planlarının değişip değişmediğini kontrol edin. MariaDB’nin query optimizer’ı MySQL’inkinden farklı kararlar alabilir.
Replikasyon Yapısı Varsa
Mevcut ortamınızda MySQL 8.x master-slave replikasyonu varsa, MariaDB’ye geçişi bu yapıyı da dikkate alarak planlamanız gerekiyor. MySQL 8.x master ile MariaDB slave birlikte çalışmaz. GTID yapıları tamamen farklı.
Önerilen strateji şudur: önce tüm node’ları aynı anda MariaDB’ye geçirin. Bunun için bakım penceresi planlayın, replikasyonu durdurun, her node’a ayrı import yapın, sonra MariaDB’nin kendi replikasyon yapısını kurun.
# MariaDB 11.x'te replikasyon kurulumu
# Master'da
mariadb -u root -p -e "
CREATE USER 'repl_user'@'%' IDENTIFIED BY 'ReplicaPassword123';
GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%';
FLUSH PRIVILEGES;
SHOW MASTER STATUS;
"
# Slave'de
mariadb -u root -p -e "
CHANGE MASTER TO
MASTER_HOST='master_ip',
MASTER_USER='repl_user',
MASTER_PASSWORD='ReplicaPassword123',
MASTER_LOG_FILE='mariadb-bin.000001',
MASTER_LOG_POS=4;
START SLAVE;
SHOW SLAVE STATUSG
"
Performans Karşılaştırması ve Ince Ayar
Geçiş sonrası performansın MySQL’e göre farklı olabileceğini beklemelisiniz. Bazı sorgular daha hızlı, bazıları daha yavaş çalışabilir. Bu normaldir çünkü optimizer farklı çalışıyor.
Yavaş sorguları tespit edin:
# MariaDB slow query log aktifleştirme
mariadb -u root -p -e "
SET GLOBAL slow_query_log=ON;
SET GLOBAL slow_query_log_file='/var/log/mysql/mariadb-slow.log';
SET GLOBAL long_query_time=1;
SET GLOBAL log_queries_not_using_indexes=ON;
"
# Log analizi
mysqldumpslow -s t -t 20 /var/log/mysql/mariadb-slow.log
MariaDB 11.x’in EXPLAIN çıktısı MySQL’inkinden biraz farklı. EXPLAIN FORMAT=JSON her iki sistemde de kullanılabilir ve daha detaylı bilgi verir.
InnoDB buffer pool boyutunu sistem RAM’ine göre ayarlayın. Genel kural: toplam RAM’in %70-80’i. Ama MariaDB’nin Aria storage engine’i de memory kullanıyor, bunu hesaba katın.
Geri Dönüş Planı
Her migration’da geri dönüş planı şart. MySQL 8.x’ten MariaDB’ye geçişten MariaDB’den MySQL’e geri dönmek zordur çünkü MariaDB’nin bazı özellikleri MySQL’de yok. Bu yüzden şunları yapın:
- MySQL 8.x sunucunuzu en az 2 hafta kapatmayın, sadece uygulama trafiğini kesin.
- MariaDB’de değiştirilmis verileri MySQL’e geri taşımak için düzenli mysqldump alın.
- Uygulama yapılandırmasında database host’u tek bir yerde tutun, hızlı geçiş yapabilin.
- Monitoring’i artırın: hata logları, yavaş sorgular, connection sayıları.
Sonuç
MySQL 8.x’ten MariaDB 11.x/12.x’e geçiş “mysqldump al, import et” kadar basit değil, ama sistematik yaklaşıldığında yönetilebilir bir süreç. En kritik noktaları özetlemek gerekirse:
- Collation farklılıkları en sık karşılaşılan sorun.
utf8mb4_0900_ai_cikullanıyorsanız mutlaka değiştirin. - Authentication plugin farkını göz ardı etmeyin. Uygulama kullanıcılarını MariaDB’de yeniden oluşturun.
- Dump dosyasını temizlemeden import etmeyin.
--set-gtid-purged=OFFve--column-statistics=0parametrelerini kullanın. - Stored procedure ve function’ları ayrıca test edin. Özellikle JSON ve window function kullananlar.
- Staging ortamında tam geçiş yapıp uygulama testlerini tamamlamadan production’a geçmeyin.
- Geri dönüş planınız olsun. İlk 2 haftada eski MySQL sunucusunu açık tutun.
Bu geçişi birkaç kez yaptım, her seferinde farklı bir sürprizle karşılaştım. Ama iyi hazırlanıldığında sonuç genellikle olumlu. MariaDB 11.x, özellikle Temporal Tables, Window Functions ve Sequences gibi özelliklerle MySQL 8.x’e kıyasla bazı kullanım senaryolarında gerçekten daha iyi bir seçenek. Lisans maliyeti avantajını da düşündüğünüzde geçiş genellikle değer.
