vitessio/vitess · error
binlog stream client charset (%v) doesn't match server (%v)
Error message
binlog stream client charset (%v) doesn't match server (%v)
What it means
Vitess does not support a MySQL server whose default charset differs from the charset the binlog-streaming client was configured with. When Stream (via StreamKeyRange/StreamTables) starts, it compares the client-provided charset against the server's charset via proto.Equal and aborts on mismatch. This is treated as a configuration error even though filtered replication might otherwise tolerate it, because per-statement charset info assumes consistent defaults.
Source
Thrown at go/vt/binlog/binlog_streamer.go:208
return err
}
defer bls.conn.Close()
// Check that the default charsets match, if the client specified one.
// Note that Streamer uses the settings for the 'dba' user, while
// BinlogPlayer uses the 'filtered' user, so those are the ones whose charset
// must match. Filtered replication should still succeed even with a default
// mismatch, since we pass per-statement charset info. However, Vitess in
// general doesn't support servers with different default charsets, so we
// treat it as a configuration error.
if bls.clientCharset != nil {
cs, err := mysql.GetCharset(bls.conn.Conn)
if err != nil {
return fmt.Errorf("can't get charset to check binlog stream: %v", err)
}
log.Info(fmt.Sprintf("binlog stream client charset = %v, server charset = %v", bls.clientCharset, cs))
if !proto.Equal(cs, bls.clientCharset) {
return fmt.Errorf("binlog stream client charset (%v) doesn't match server (%v)", bls.clientCharset, cs)
}
}
var events <-chan mysql.BinlogEvent
var errs <-chan error
if bls.timestamp != 0 {
// MySQL 5.6 only: We are going to start reading the
// logs from the beginning of a binlog file. That is
// going to send us the PREVIOUS_GTIDS_EVENT that
// contains the starting GTIDSet, and we will save
// that as the current position.
bls.usePreviousGTIDs = true
events, errs, err = bls.conn.StartBinlogDumpFromBinlogBeforeTimestamp(ctx, bls.timestamp)
} else if !bls.startPos.IsZero() {
// MySQL 5.6 only: we are starting from a random
// binlog position. It turns out we will receive a
// PREVIOUS_GTIDS_EVENT event, that has a GTIDSet
// extracted from the binlogs. It is not related toView on GitHub (pinned to 01a25a7d17)
Solutions
- Align the server default charset (character-set-server / collation-server) with the client charset Vitess is configured with, or vice versa
- Update the vttablet binlog source charset config to match the server's default charset
- Reinitialize or correct charset settings on the target MySQL instances so the dba-user connection reports the expected charset
- After changing my.cnf, restart MySQL and the tablet so the new charset takes effect
Example fix
// before (my.cnf) character-set-server = latin1 // after character-set-server = utf8mb4
Defensive patterns
Strategy: validation
Validate before calling
serverCS, err := mysql.GetCharset(conn.Conn)
if err != nil { return err }
if !proto.Equal(serverCS, configuredCharset) {
return fmt.Errorf("charset mismatch: client %v vs server %v", configuredCharset, serverCS)
} Try / catch
if err := streamer.Stream(ctx); err != nil {
if strings.Contains(err.Error(), "doesn't match server") {
// fix charset configuration; streaming will never succeed until then
}
} Prevention
- Keep character-set-server identical across all MySQL instances in the topology
- Align vttablet binlog-source charset config with the server default
- Avoid changing server charset without a coordinated rollout
- Validate charsets during cluster provisioning
When it happens
Trigger: Calling Stream with a clientCharset set (via NewStreamer) that is not proto.Equal to the server's default charset reported by mysql.GetCharset on the dba connection — e.g. client charset utf8mb4 vs server default latin1.
Common situations: Provisioned MySQL server with a different default charset than the vttablet/binlog source config; charset changed on the server (my.cnf character_set_server) after tablets were deployed; mixing tablets configured for different charsets in a cluster.
Related errors
- can't get charset to check binlog stream: %v
- GetPreviousGTIDs: previous GTIDs not found
- SHOW BINARY LOGS returned no rows
- partial row image encountered: ensure binlog_row_image is se
- startPos.GTIDSet is wrong type - expected filePosGTID, got:
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/6de3b9fb3783265a.
Report an issue: GitHub.