vitessio/vitess · error
mysqld_shutdown hook failed: %v
Error message
mysqld_shutdown hook failed: %v
What it means
During executeShutdown, Vitess runs the optional 'mysqld_shutdown' hook to customize how mysqld is stopped. If the hook returns any status other than success or does-not-exist, shutdown is aborted immediately and this error is returned. Unlike the preflight hook, this one fires mid-shutdown, so mysqld may already be in the middle of stopping when it fails.
Source
Thrown at go/vt/mysqlctl/mysqld.go:1177
// The error is only suppressed when the wait below will run:
// for waitForMysqld=false callers a nil return would claim a
// shutdown nothing verified, so they get the error as before.
if !mysqladminAbortedWaiting(output) {
// The SHUTDOWN command was never delivered.
return false, err
}
if !waitForMysqld {
// Delivered, but nothing below will verify the outcome.
return true, err
}
log.Warn("mysqladmin gave up waiting for mysqld to stop, waiting on pid/socket files instead", slog.Any("error", err))
var cancel context.CancelFunc
ctx, cancel = boundShutdownWaitContext(ctx)
defer cancel()
}
default:
// hook failed, we report error
return false, fmt.Errorf("mysqld_shutdown hook failed: %v", hr.String())
}
// Wait for mysqld to really stop. Use the socket and pid files as a
// proxy for that since we can't call wait() in a process we
// didn't start.
if waitForMysqld {
log.Info(fmt.Sprintf("Mysqld.Shutdown: waiting for socket file (%v) and pid file (%v) to disappear", cnf.SocketFile, cnf.PidFile))
if err := waitForMysqldExit(ctx, cnf.SocketFile, cnf.PidFile); err != nil {
return true, err
}
}
return true, nil
}
// StartAfterExit waits for a mysqld process that shut itself down (e.g. after a
// CLONE operation) to fully exit, then starts a new one. It polls for the
// disappearance of the socket and pid files before calling Start.
func (mysqld *Mysqld) StartAfterExit(ctx context.Context, cnf *Mycnf) error {View on GitHub (pinned to 01a25a7d17)
Solutions
- Read the hook's exit status and output embedded in the error (hr.String()) and fix the custom shutdown script accordingly.
- Test the hook script manually on the host with the same user and environment Vitess runs under.
- Ensure the script handles the already-stopped-mysqld case gracefully (idempotent exit 0).
- Remove the hook if it is no longer needed so the default shutdown path is used.
Example fix
// before mysqladmin -p wrongpass shutdown || exit 1 // after mysqladmin shutdown 2>/dev/null || exit 0 # already stopped is OK
Defensive patterns
Strategy: try-catch
Validate before calling
hr := hook.NewHook("mysqld_shutdown").ExecuteContext(ctx)
if hr.ExitStatus != hook.HOOK_SUCCESS && hr.ExitStatus != hook.HOOK_DOES_NOT_EXIST {
return fmt.Errorf("shutdown hook not ready: %s", hr.String())
} Type guard
func shutdownHookOK(hr *hook.HookResult) bool {
return hr.ExitStatus == hook.HOOK_SUCCESS || hr.ExitStatus == hook.HOOK_DOES_NOT_EXIST
} Try / catch
err := mysqld.Shutdown(ctx, cnf, true, timeout)
if err != nil && strings.Contains(err.Error(), "mysqld_shutdown hook failed") {
// parse hr from message; if mysqld is already partially stopping, poll socket file removal
} Prevention
- Make shutdown hook scripts idempotent (succeed when mysqld is already stopped).
- Test hooks under the exact user/environment Vitess runs with.
- Avoid long-running logic in shutdown hooks; keep them under the shutdown timeout.
- Remove obsolete hooks from the hook directory rather than leaving broken scripts.
When it happens
Trigger: Mysqld.executeShutdown (via shutdownWithReplicaCrashSafety) invokes the mysqld_shutdown hook; the hook script exits with a non-success status (other than HOOK_SUCCESS / HOOK_DOES_NOT_EXIST).
Common situations: A custom shutdown script (e.g. using mysqladmin shutdown with special flags) fails because of wrong credentials or mysqld already gone; the hook times out; the script's environment (PATH, config) differs from what it expects under Vitess.
Related errors
- preflight_mysqld_shutdown hook failed: %v
- can't stat mysqld socket file: %v
- %v: %w, output: %v
- failed to initialize mysqld: %v
- failed to initialize clone support: %v
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/8dc6d268a33a9fe7.
Report an issue: GitHub.