Keeping the MySQL or MariaDB server time zone predictable prevents confusing timestamp shifts in application logs, scheduled jobs, replication checks, and user-facing reports when the same data is read across multiple regions.
Both databases track three related values: the OS-derived @@system_time_zone, the server-wide default @@global.time_zone, and each connection's @@session.time_zone. New sessions inherit the global value, functions such as NOW() follow the session setting, and TIMESTAMP columns are converted between the session time zone and UTC while DATETIME values stay as stored.
Examples below use Linux package installs and systemd units because that is where option files and service restarts are easiest to verify. The default global value is usually SYSTEM, so the server follows the host time zone until you set an explicit override; global changes affect only new connections; named zones such as Europe/Berlin require loaded time zone tables; and replicated servers should not mix different host time zones while still relying on SYSTEM. For stable cross-region behavior, keep the database on +00:00 unless the server truly must operate in a local civil time zone.
In current MySQL releases, SET GLOBAL time_zone requires SYSTEM_VARIABLES_ADMIN or the deprecated SUPER privilege. Current MariaDB documentation lists SUPER for the same operation.
$ client_bin=$(command -v mariadb || command -v mysql) $ "$client_bin" --table --user=root --password --execute "SELECT @@global.time_zone AS global_tz, @@session.time_zone AS session_tz, @@system_time_zone AS system_tz;" +-----------+------------+-----------+ | global_tz | session_tz | system_tz | +-----------+------------+-----------+ | SYSTEM | SYSTEM | UTC | +-----------+------------+-----------+
If the local root account uses Unix socket authentication, replace the explicit credentials with sudo mariadb or sudo mysql.
$ "$client_bin" --table --user=root --password --execute "SET GLOBAL time_zone = '+00:00'; SET SESSION time_zone = '+00:00'; SELECT @@global.time_zone AS global_tz, @@session.time_zone AS session_tz, NOW() AS now_session, UTC_TIMESTAMP() AS now_utc;" +-----------+------------+---------------------+---------------------+ | global_tz | session_tz | now_session | now_utc | +-----------+------------+---------------------+---------------------+ | +00:00 | +00:00 | 2026-04-09 21:32:47 | 2026-04-09 21:32:47 | +-----------+------------+---------------------+---------------------+
SET GLOBAL changes the default only for new connections. Existing sessions keep their current session time zone until they reconnect or run SET SESSION time_zone = ... themselves.
UTC_TIMESTAMP() does not follow the session time zone, so it is a useful comparison when confirming the change.
$ "$client_bin" --table --user=root --password --execute "SELECT @@global.time_zone AS global_tz, @@session.time_zone AS session_tz, @@system_time_zone AS system_tz;" +-----------+------------+-----------+ | global_tz | session_tz | system_tz | +-----------+------------+-----------+ | +00:00 | +00:00 | UTC | +-----------+------------+-----------+
$ server_bin=$(command -v mariadbd || command -v mysqld) $ sudo "$server_bin" --verbose --help 2>/dev/null | sed -n '/Default options are read from the following files in the given order:/,+3p' Default options are read from the following files in the given order: /etc/my.cnf /etc/mysql/my.cnf ~/.my.cnf ##### snipped #####
Use the last server include directory that the base file actually reads, such as /etc/mysql/mariadb.conf.d/, /etc/mysql/mysql.conf.d/, or /etc/mysql/conf.d/. This guide covers that discovery in more detail.
$ sudoedit /etc/mysql/conf.d/time-zone.cnf
[mysqld] is the safest cross-compatible option group. MariaDB also reads [mariadb] and [mariadbd].
In option files, MySQL and MariaDB treat dashes and underscores in option names as equivalent, so default-time-zone and default_time_zone are interchangeable spellings.
[mysqld] default-time-zone = '+00:00'
A typo or a bad option group can stop the database server from starting. Keep the change in a small dedicated override file so it is easy to remove if startup fails.
$ systemctl list-unit-files --type=service | grep --extended-regexp '^(mysql|mariadb|mysqld)\\.service' mariadb.service enabled enabled $ sudo systemctl restart mariadb $ systemctl is-active mariadb active
Replace mariadb with the discovered unit name, which may be mysql or mysqld on other packages.
$ "$client_bin" --table --user=root --password --execute "SELECT @@global.time_zone AS global_tz, @@session.time_zone AS session_tz, @@system_time_zone AS system_tz;" +-----------+------------+-----------+ | global_tz | session_tz | system_tz | +-----------+------------+-----------+ | +00:00 | +00:00 | UTC | +-----------+------------+-----------+
$ "$client_bin" --table --user=root --password --execute "SELECT COUNT(*) AS zone_rows FROM mysql.time_zone_name;" +-----------+ | zone_rows | +-----------+ | 0 | +-----------+
Both products create the tables by default, but leave them unpopulated until you load zoneinfo data.
$ tz_loader=$(command -v mariadb-tzinfo-to-sql || command -v mysql_tzinfo_to_sql) $ "$tz_loader" /usr/share/zoneinfo | "$client_bin" --user=root --password mysql
MySQL documentation recommends restarting the server after loading or reloading the time zone tables so cached time zone data is refreshed. A restart is also the safest cross-engine choice before retrying a named zone.
$ sudo systemctl restart mariadb $ "$client_bin" --table --user=root --password --execute "SET GLOBAL time_zone = 'Europe/Berlin'; SELECT @@global.time_zone AS global_tz;" +---------------+ | global_tz | +---------------+ | Europe/Berlin | +---------------+
Use a named zone only when the server must follow local daylight-saving rules automatically. Otherwise, staying on +00:00 is usually simpler and safer.