vitessio/vitess · error
cannot use backup between different flavors: %q vs. %q
Error message
cannot use backup between different flavors: %q vs. %q
What it means
The MySQL backup engine validates that a backup taken on one flavor (e.g. MySQL vs MariaDB vs Percona) can only be restored on the same flavor. This error comes from the compatibility check comparing the 'from' and 'to' version strings; restoring across flavors is unsupported because data layout, redo/inno formats, and utilities differ.
Source
Thrown at go/vt/mysqlctl/backupengine.go:675
func validateMySQLVersionUpgradeCompatible(to string, from string, upgradeSafe bool) error {
// It's always safe to use the same version.
if to == from {
return nil
}
flavorTo, parsedTo, err := ParseVersionString(to)
if err != nil {
return err
}
flavorFrom, parsedFrom, err := ParseVersionString(from)
if err != nil {
return err
}
if flavorTo != flavorFrom {
return fmt.Errorf("cannot use backup between different flavors: %q vs. %q", from, to)
}
if parsedTo == parsedFrom {
return nil
}
// If we're not on the same LTS stream, we have to do additional checks to see if it's safe to
// to upgrade. It can only be one newer LTS version for the destination and the backup
// has to be marked as upgrade safe.
// If something is across different LTS streams and not upgrade safe, we can't use it.
if !parsedFrom.isSameRelease(parsedTo) {
if !upgradeSafe {
if parsedTo.atLeast(parsedFrom) {
return fmt.Errorf("running MySQL version %q is newer than backup MySQL version %q which is not safe to upgrade", to, from)
}
return fmt.Errorf("running MySQL version %q is older than backup MySQL version %q", to, from)
}View on GitHub (pinned to 01a25a7d17)
Solutions
- Provision the restore target with the same MySQL flavor as the backup.
- Take a fresh backup using the new flavor and restore from that instead.
- If flavor migration is truly needed, do a logical migration (export/import) rather than a binary restore.
- Fix version config so the correct from/to flavor strings are passed (check ParseVersionString inputs).
Example fix
// before // restore backup from="MySQL8.0.35" onto to="MariaDB10.6" // returns: cannot use backup between different flavors // after // restore onto to="MySQL8.0.35" (same flavor), or take a new backup on MariaDB first
Defensive patterns
Strategy: validation
Validate before calling
fromFlavor, _, err := mysqlctl.ParseVersionString(from)
if err != nil {
return err
}
toFlavor, _, err := mysqlctl.ParseVersionString(to)
if err != nil {
return err
}
if fromFlavor != toFlavor {
return fmt.Errorf("backup flavor %q != target flavor %q", from, to)
} Try / catch
err := engine.RestoreData(ctx, h, bh, localMetadata, dir, restartMySql)
if err != nil && strings.Contains(err.Error(), "different flavors") {
return fmt.Errorf("take a fresh backup on the target flavor: %w", err)
} Prevention
- Keep the mysqld flavor consistent across the cluster and backup targets
- After a flavor migration, take fresh backups before allowing restores
- Verify version strings with mysqlctl.ParseVersionString in provisioning checks
When it happens
Trigger: Calling restore (e.g. RestoreData / backupengine restore path) with from="MariaDB10.6" and to="MySQL8.0" (or vice versa); also occurs when a tablet's mysqld was upgraded/replaced with a different flavor while old backups exist.
Common situations: Migrating a cluster between MySQL and Percona/MariaDB, provisioning mistakes where new tablets run a different flavor than the one used to take backups, mistaken mysqld version configuration in vttablet/vtctld.
Related errors
- running MySQL version %q is newer than backup MySQL version
- running MySQL version %q is older than backup MySQL version
- running MySQL version %q is too new for backup MySQL version
- mysqld >= 8.0.21 required to disable the redo log
- AbortBackup cannot be called on read-only backup
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/9ad7b6ef94aff587.
Report an issue: GitHub.