Fix Django "Are Time Zone Definitions for Your Database Installed?"
Fix the Django ValueError saying the database returned an invalid datetime value and asking whether time zone definitions for your database are installed: load MySQL or MariaDB time zone tables, including on Docker, RDS, and Cloud SQL.
Problem statement
A queryset that groups or filters by date works on PostgreSQL and SQLite but crashes on MySQL or MariaDB:
ValueError: Database returned an invalid datetime value.
Are time zone definitions for your database installed?
It typically appears with TruncDate, TruncMonth, __date, __year lookups, dates(), and the admin's date_hierarchy. With USE_TZ = True, Django asks MySQL to convert UTC values into the current time zone using CONVERT_TZ(col, 'UTC', 'Europe/Berlin'). If MySQL does not know what Europe/Berlin means, CONVERT_TZ returns NULL, and Django cannot turn NULL into a datetime.
- Check:
SELECT CONVERT_TZ('2026-01-01 12:00', 'UTC', 'Europe/Berlin');If it returnsNULL, the tables are empty. - On a self-managed server, load them:
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql. - In Docker, run the same command inside the container once, or use an image that has them loaded.
- On Amazon RDS and Cloud SQL, the tables are preloaded; check the zone name and the user's privileges instead.
- Reload them after major OS or MySQL upgrades so new zone rules apply.
Step-by-step solution
1. Confirm the diagnosis
SELECT CONVERT_TZ('2026-01-01 12:00:00', 'UTC', 'Europe/Berlin');
SELECT COUNT(*) FROM mysql.time_zone_name;
A NULL result and a count of 0 confirm the tables were never loaded. MySQL installs the schema for them but not the data.
2. Load the time zone tables on a server
On Debian or Ubuntu, the zoneinfo database is in /usr/share/zoneinfo:
mysql_tzinfo_to_sql /usr/share/zoneinfo | sudo mysql -u root mysql
sudo systemctl restart mysql
Warnings about files such as iso3166.tab or leap-seconds.list are harmless. On MariaDB the tool is mariadb-tzinfo-to-sql on newer versions; the old name usually still works as a symlink.
3. Load them in Docker
The official mysql image does not load zone data by default. Load it once into the data volume:
docker compose exec db sh -c 'mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p"$MYSQL_ROOT_PASSWORD" mysql'
To make new environments correct automatically, add an init script. Files in /docker-entrypoint-initdb.d/ run only when the data directory is empty:
#!/bin/sh
# docker/mysql-init/10-timezones.sh
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p"$MYSQL_ROOT_PASSWORD" mysql
Mount it in Compose with ./docker/mysql-init:/docker-entrypoint-initdb.d:ro. CI services need the same step, or tests that use date lookups fail only in CI.
4. Managed databases
Amazon RDS, Aurora MySQL, Google Cloud SQL, and Azure Database for MySQL ship with time zone tables loaded, and you cannot write to the mysql schema anyway. If you still get the error there:
- Check that the zone name in
TIME_ZONEor the activated zone is a valid IANA name such asAmerica/New_York, notEST5EDTtypos or Windows names. - Make sure the connection is not going to a different, self-hosted database by accident.
5. Or avoid the conversion
If all users share UTC, TIME_ZONE = "UTC" makes Django skip CONVERT_TZ for the default zone. This is a workaround, not a fix: any timezone.activate() call for another zone will hit the error again.
Explanation
PostgreSQL ships its own time zone database and converts with AT TIME ZONE out of the box. MySQL separates the conversion function from the data. CONVERT_TZ accepts numeric offsets like '+01:00' without tables, but named zones need the rows in mysql.time_zone*. Django uses named zones because offsets are wrong for half the year in any zone with daylight saving time. When the lookup returns NULL, the MySQL backend raises the ValueError with the hint about time zone definitions.
Edge cases / notes
- Replication. Load the tables on the primary; they replicate like other data. Loading them only on a replica breaks queries routed to the primary.
- Upgrades. Zone rules change a few times a year. Reloading the tables after OS tzdata updates keeps conversions correct for recent rule changes.
- Privileges. The application user does not need access to the
mysqlschema;CONVERT_TZworks for all users once the data exists.
Next steps
- Review your full MySQL setup with Configure Django With MySQL in Production.
- For display problems on any database, see Fix Wrong Times in Django Production.
- Comparing databases? Read PostgreSQL vs MySQL for Django.
FAQ
Why does it work with PostgreSQL but not MySQL?
PostgreSQL includes time zone data. MySQL needs it loaded into system tables separately.
Can I set USE_TZ = False instead?
That removes the conversion but stores naive local times, which causes problems with daylight saving time and multiple regions. Load the tables instead.
Do I need to restart MySQL after loading?
Usually not, but a restart or FLUSH TABLES makes sure cached zone data is refreshed.
Is the error caused by the Django version?
No. Every supported Django version uses CONVERT_TZ on MySQL when USE_TZ = True.