@CreatedDate annotation does not work with MySQL
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
When @CreatedDate seems to “not work with MySQL,” the problem is usually not MySQL itself. @CreatedDate is a Spring Data auditing feature that sets the field value in the application before the insert reaches the database. If the timestamp stays null, the usual causes are missing auditing configuration, missing entity listeners, incompatible field mapping, or conflicting database defaults.
What @CreatedDate Actually Does
@CreatedDate does not tell MySQL to generate a timestamp automatically. Instead, Spring Data populates the property during persistence when auditing is enabled.
A typical entity looks like this:
If auditing is configured correctly, createdAt gets set before Hibernate issues the insert.
Auditing Must Be Enabled
The most common missing piece is @EnableJpaAuditing.
Without this, @CreatedDate is just an annotation on a field. Nothing activates the auditing logic.
The Entity Listener Must Be Registered
Even with auditing enabled globally, the entity also needs the auditing listener, either directly or through a mapped superclass.
If that listener is missing, the audit fields are never populated. This is one of the most common reasons people blame the database even though the issue is at the ORM layer.
Choose a Supported Date Type
Spring Data auditing works best with standard temporal types such as:
- '
Instant' - '
LocalDateTime' - '
OffsetDateTime' - '
Date'
A common modern choice is Instant:
Make sure the column type in MySQL matches how your ORM maps that Java type. The important part is consistency between the Java field and the database column.
MySQL Default Timestamps Can Conflict with App Auditing
If the database column also has its own default such as DEFAULT CURRENT_TIMESTAMP, you now have two potential sources of truth:
- application-side auditing
- database-side default generation
That can be okay, but it often causes confusion during debugging. If you want Spring Data to own the value, let Spring Data own it cleanly and avoid depending on MySQL defaults for the same column.
Example column intent:
Then let the application populate it through auditing.
Time Zone Issues Are Different from Null Issues
Sometimes @CreatedDate “works” but the saved time looks wrong. That is a timezone problem, not an auditing failure. The field was populated, but the value was converted or displayed differently than expected.
Practical checks include:
- JVM timezone
- JDBC connection timezone settings
- MySQL server timezone
- application choice of
Instantversus local date-time types
If the field is null, focus on auditing configuration first. If the field is populated but shifted, focus on timezone alignment.
Debugging Checklist
When createdAt is null after save, verify these items in order:
@EnableJpaAuditingis present@EntityListeners(AuditingEntityListener.class)is present- the entity is being saved through Spring Data JPA, not bypassing the managed lifecycle
- the field type is supported and mapped correctly
- the column is not being overwritten by another persistence rule
That checklist usually resolves the problem faster than changing MySQL column definitions randomly.
Example End-to-End
Repository and save flow:
If auditing is wired correctly, createdAt will be set on insert without any manual assignment.
Common Pitfalls
The biggest mistake is assuming @CreatedDate is a MySQL feature rather than a Spring Data auditing feature. Another is enabling auditing globally but forgetting the entity listener on the entity or base class. Developers also often mix application-generated timestamps with database defaults and then struggle to understand which side is supposed to win. Finally, timezone mismatch can distract from the real issue if the field is populated but displayed differently than expected.
Summary
- '
@CreatedDateis handled by Spring Data auditing, not by MySQL.' - Enable auditing with
@EnableJpaAuditing. - Register
AuditingEntityListeneron the entity or mapped superclass. - Use a supported temporal field type and a consistent column mapping.
- Treat null timestamps, conflicting defaults, and timezone shifts as different problems with different fixes.

