vitessio/vitess · error

running MySQL version %q is older than backup MySQL version

Error message

running MySQL version %q is older than backup MySQL version %q

What it means

Thrown by checkRestoreVersion when the running MySQL version is older than the version the backup was taken with, across different release streams, and the backup is not upgrade-safe. Downgrading across release streams by restoring newer data files onto an older MySQL binary is unsupported, so the restore is aborted.

Source

Thrown at go/vt/mysqlctl/backupengine.go:692

	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)
		}

		// Alright, we're across different LTS streams and the backup is upgrade safe.
		// We can only upgrade to the next LTS version.
		for i, ltsVersion := range ltsVersions {
			if parsedFrom.isSameRelease(ltsVersion) {
				if i < len(ltsVersions)-1 && parsedTo.isSameRelease(ltsVersions[i+1]) {
					return nil
				}
				if parsedTo.atLeast(parsedFrom) {
					return fmt.Errorf("running MySQL version %q is too new for backup MySQL version %q", to, from)
				}
				return fmt.Errorf("running MySQL version %q is older than backup MySQL version %q", to, from)
			}
		}
		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)
		}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Upgrade the tablet's mysqld to a version at least as new as the backup's MySQL version, then restore.
  2. Take a fresh backup from a tablet running the older MySQL version and restore from that.
  3. Align the fleet on one MySQL release stream so backups and tablets match.
  4. Check the backup manifest's MySQLVersion for mis-recording if versions were expected to match.

Example fix

// before: 8.4.2 backup, tablet on 8.0.36 -> error
// after: upgrade tablet mysqld to 8.4.2 (>= backup version) and restore
Defensive patterns

Strategy: validation

Validate before calling

backupVer := parseVersion(backupManifest.MySQLVersion)
runningVer := parseVersion(getRunningMySQLVersion())
if !runningVer.atLeast(backupVer) {
    return errors.New("tablet MySQL older than backup version: upgrade tablet or use older backup")
}

Prevention

When it happens

Trigger: Restore where parsedTo.atLeast(parsedFrom) is false (running version strictly older than backup version), versions are not same-release, and the backup manifest lacks the upgrade-safe marker.

Common situations: A tablet was provisioned with an older MySQL than the one used to produce the backup (e.g. backup from 8.4.x, tablet runs 8.0.y); mixed versions after a partial rollout/rollback of a MySQL upgrade.

Related errors


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