vitessio/vitess · error

can't dial mysqlctld

Error message

can't dial mysqlctld: %v

What it means

Mysqld.RunMysqlUpgrade was asked to execute remotely on a mysqlctld server (socketFile set), but the mysqlctl RPC client could not dial that server over the unix socket. The upgrade request never reached mysqlctld.

Solutions

  1. Confirm mysqlctld is running and listening on the configured unix socket (`ls -l <socketFile>`)
  2. Correct the --mysqlctl_remote_socket flag value
  3. Restart mysqlctld, then retry the upgrade
  4. If you don't need remote execution, unset the socket flag so RunMysqlUpgrade runs locally

Example fix

// before: remote mode with stale socket
return mysqld.RunMysqlUpgrade(ctx) // socketFile points to dead server
// after: restart mysqlctld first
if _, err := os.Stat(socketFile); err != nil {
    log.Warning("mysqlctld socket missing, running upgrade locally")
}
return mysqld.RunMysqlUpgrade(ctx)
Defensive patterns

Strategy: retry

Validate before calling

if _, err := os.Stat(socketFile); err != nil {
    return fmt.Errorf("mysqlctld socket %s missing; is mysqlctld running?", socketFile)
}

Try / catch

err := mysqld.RunMysqlUpgrade(ctx)
if strings.Contains(err.Error(), "can't dial mysqlctld") {
    // wait for mysqlctld and retry once
    time.Sleep(2 * time.Second)
    err = mysqld.RunMysqlUpgrade(ctx)
}

Prevention

When it happens

Trigger: Calling Mysqld.RunMysqlUpgrade while the mysqlctl remote-action socket (-mysqlctl_remote_socket / socketFile) is configured and mysqlctld is not running, has exited, or the socket path is wrong.

Common situations: mysqlctld crashed or was restarted between actions; wrong socket file path in flags; permission denied on /tmp socket; using remote-action mode without launching mysqlctld.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


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

Appendix: source

Thrown at go/vt/mysqlctl/mysqld.go:417

	}
	ver.Patch, err = strconv.Atoi(string(v[3]))
	if err != nil {
		return flavor, ver, fmt.Errorf("could not parse server version from: %s", version)
	}

	return
}

// RunMysqlUpgrade will run the mysql_upgrade program on the current
// install.  Will be called only when mysqld is running with no
// network and no grant tables.
func (mysqld *Mysqld) RunMysqlUpgrade(ctx context.Context) error {
	// Execute as remote action on mysqlctld if requested.
	if socketFile != "" {
		log.Info(fmt.Sprintf("executing Mysqld.RunMysqlUpgrade() remotely via mysqlctld server: %v", socketFile))
		client, err := mysqlctlclient.New(ctx, "unix", socketFile)
		if err != nil {
			return fmt.Errorf("can't dial mysqlctld: %v", err)
		}
		defer client.Close()
		return client.RunMysqlUpgrade(ctx)
	}

	if mysqld.capabilities.hasMySQLUpgradeInServer() {
		log.Warn("MySQL version has built-in upgrade, skipping RunMySQLUpgrade")
		return nil
	}

	// Since we started mysql with --skip-grant-tables, we should
	// be able to run mysql_upgrade without any valid user or
	// password. However, mysql_upgrade executes a 'flush
	// privileges' right in the middle, and then subsequent
	// commands fail if we don't use valid credentials. So let's
	// use dba credentials.
	params, err := mysqld.dbcfgs.DbaConnector().MysqlParams()
	if err != nil {

View on GitHub (pinned to 01a25a7d17)