vitessio/vitess · error
preflight_mysqld_shutdown hook failed: %v
Error message
preflight_mysqld_shutdown hook failed: %v
What it means
Before shutting down mysqld, Vitess runs an optional user-supplied 'preflight_mysqld_shutdown' hook. If the hook exits with any status other than HOOK_SUCCESS or HOOK_DOES_NOT_EXIST, Shutdown aborts before stopping mysqld and returns this error containing the hook's result string. It is a deliberate extension point failure — the operator's pre-shutdown validation refused the shutdown.
Source
Thrown at go/vt/mysqlctl/mysqld.go:801
}
defer releaseFlock()
}
// possibly mysql is already shutdown, check for a few files first
if mysqldAlreadyStopped(cnf) {
log.Warn("assuming mysqld already shut down - no socket, no pid file found")
return nil
}
// try the preflight mysqld shutdown hook, if any
h := hook.NewSimpleHook("preflight_mysqld_shutdown")
hr := h.ExecuteContext(ctx)
switch hr.ExitStatus {
case hook.HOOK_SUCCESS, hook.HOOK_DOES_NOT_EXIST:
// hook exists and worked, or else does not exist.
default:
// hook failed, we report error
return fmt.Errorf("preflight_mysqld_shutdown hook failed: %v", hr.String())
}
return mysqld.shutdownWithReplicaCrashSafety(ctx, preparationBudget, func() (bool, error) {
return mysqld.executeShutdown(ctx, cnf, waitForMysqld, shutdownTimeout)
})
}
// replicaShutdownPreparationBudget returns how long the replica crash-safety
// preparation may take for the given shutdown timeout. A zero (or negative)
// shutdown timeout means the caller wants an immediate, no-wait shutdown
// (mysqladmin --shutdown-timeout=0): honor that by granting the preparation
// no budget at all rather than its default one.
func replicaShutdownPreparationBudget(shutdownTimeout time.Duration) time.Duration {
if shutdownTimeout <= 0 {
return 0
}
return min(replicaShutdownPreparationTimeout, shutdownTimeout)
}View on GitHub (pinned to 01a25a7d17)
Solutions
- Inspect hr in the error message for the hook's exit status, stdout and stderr to see why the preflight script failed.
- Fix the condition the preflight hook checks (e.g. wait for replica lag to drain, take a backup) and retry the shutdown.
- Correct or disable the hook script if it is malfunctioning (bad shebang, wrong exit code conventions).
- Remember hooks returning HOOK_DOES_NOT_EXIST are fine — only a real non-success exit blocks shutdown.
Example fix
// before #!/bin/sh exit 1 # debugging leftover // after #!/bin/sh # verify replica is caught up mysql -e 'SELECT 1' || exit 1 exit 0
Defensive patterns
Strategy: validation
Validate before calling
hr := hook.NewHook("preflight_mysqld_shutdown").ExecuteContext(ctx)
if hr.ExitStatus != hook.HOOK_SUCCESS && hr.ExitStatus != hook.HOOK_DOES_NOT_EXIST {
log.Infof("preflight would fail: %s", hr.String())
} Type guard
func hookSucceeded(hr *hook.HookResult) bool {
return hr.ExitStatus == hook.HOOK_SUCCESS || hr.ExitStatus == hook.HOOK_DOES_NOT_EXIST
} Try / catch
if err := mysqld.Shutdown(ctx, cnf, true, timeout); err != nil && strings.Contains(err.Error(), "preflight_mysqld_shutdown hook failed") {
// read hr details from message, resolve the blocking condition, retry
} Prevention
- Dry-run preflight hooks manually before wiring them into production shutdown paths.
- Use only documented hook exit codes (0 success); avoid ad-hoc non-zero codes.
- Keep preflight hooks fast and idempotent.
- Log hook stdout/stderr to a persistent location for postmortems.
When it happens
Trigger: Mysqld.Shutdown executes the preflight_mysqld_shutdown hook via hook.ExecuteContext; the hook script exits non-zero (not 0/SUCCESS and not DOES_NOT_EXIST), e.g. exit status 1 from a custom guard script.
Common situations: A site-specific preflight script checks replication lag or backup state and fails on a laggy replica; the hook script itself has a bug or wrong interpreter path; the hook returns an unexpected status code such as HOOK_PARTIAL_SUCCESS being treated as failure.
Related errors
- mysqld_shutdown hook failed: %v
- no client certs for connection
- unexpected: query ended without no results and no error
- overflow
- mysqld >= 8.0.21 required to disable the redo log
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/3526704c956fe1f9.
Report an issue: GitHub.