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

  1. Provision the restore target with the same MySQL flavor as the backup.
  2. Take a fresh backup using the new flavor and restore from that instead.
  3. If flavor migration is truly needed, do a logical migration (export/import) rather than a binary restore.
  4. 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

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


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/9ad7b6ef94aff587. Report an issue: GitHub.