Library / SDK
go-mysql-org/go-mysql avatar
go-mysql-org/go-mysql

go-mysql: A Go Library for MySQL Replication, Canal Sync, and Protocol Handling

a powerful mysql toolset with Go

4,972 stars1,078 forksGoMIT

At a glance

What is it?
go-mysql is a pure Go library for the MySQL and MariaDB network protocol, providing binlog replication, incremental canal-based sync, a simple client, a fake server, and an alternative database/sql driver. It is for Go developers who need access to MySQL's replication stream or who want to build change-data-capture pipelines, not for those who only need basic query execution.
Who is it for?
go-mysql is the correct choice when a Go application needs to read MySQL's binlog stream, sync database changes to an external store, or implement a fake MySQL server for testing. It is not the right tool when your application only needs to run SQL queries: the standard database/sql interface with go-sql-driver/mysql is simpler for that case.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What go-mysql Provides That database/sql Does Not

The Go standard library's database/sql interface treats a MySQL server as a source of query results. It sends SQL and receives rows. go-mysql operates at a lower level: it speaks the MySQL network protocol directly, which opens up capabilities that database/sql never exposes.

The most important of these is binlog replication. MySQL's binary log records every change made to the database in a structured event stream. MySQL replicas subscribe to this stream to stay in sync with the primary. go-mysql lets a Go program act as a replica, subscribing to the binlog and receiving each INSERT, UPDATE, and DELETE event as a structured Go value. This is the foundation for building change-data-capture pipelines, cache invalidation systems, and real-time sync to non-MySQL stores.

The library is documented as a pure Go implementation, which means it has no cgo dependencies. It has been tested or deployed on Linux (amd64, s390x, arm64, arm) and FreeBSD (amd64). The go.mod requires Go 1.25. It is explicitly not compatible with TinyGo.

The library organizes its capabilities into several packages: `replication` for reading binlog events, `canal` for the higher-level incremental sync pipeline, `client` for a simple MySQL connection, `server` for a fake MySQL server, and `driver` for a database/sql-compatible alternative driver.

Binlog Replication: Reading MySQL Events as a Go Replica

The `replication` package establishes a connection to a MySQL server and subscribes to its binary log, just as a MySQL replica would. You create a `BinlogSyncerConfig` with a unique server ID, the MySQL flavor (mysql or mariadb), host, port, user, and password. The server ID must not conflict with any existing replica's ID on that server.

go
cfg := replication.BinlogSyncerConfig {
	ServerID: 100,
	Flavor:   "mysql",
	Host:     "127.0.0.1",
	Port:     3306,
	User:     "root",
	Password: "",
}
syncer := replication.NewBinlogSyncer(cfg)

Once the syncer is created, you call `StartSync` with a binlog file name and position, or use GTID-based replication. The syncer returns a streamer, and you loop over events from it. The README shows what the output looks like for common event types: RotateEvent, FormatDescriptionEvent, and QueryEvent each print the event name, timestamp, log position, event size, and relevant payload fields.

The package handles both MySQL and MariaDB. The flavor field in the config determines which protocol dialect is used. For GTID-based sync, the README documents separate methods.

Canal: Incremental MySQL Sync to External Data Stores

The `canal` package builds on the replication package to provide a higher-level abstraction for syncing MySQL data to external stores such as Redis or Elasticsearch. The README describes the two-phase approach: canal first performs an initial dump of the MySQL data, then switches to incremental binlog-based sync to keep the external store current.

You define an event handler by embedding `canal.DummyEventHandler` and implementing the `OnRow` method, which receives a `RowsEvent` containing the action (INSERT, UPDATE, DELETE) and the affected rows.

go
type MyEventHandler struct {
	canal.DummyEventHandler
}

func (h *MyEventHandler) OnRow(e *canal.RowsEvent) error {
	log.Infof("%s %v\n", e.Action, e.Rows)
	return nil
}

The canal configuration specifies the MySQL address, user, and which tables to watch. The `cfg.Dump.TableDB` and `cfg.Dump.Tables` fields narrow the scope to specific tables, which reduces both the initial dump size and the ongoing event volume.

The README points to the `go-mysql-elasticsearch` repository as an example of a complete canal-based sync implementation. Notably, canal requires ROW format binary logging. The README states that full binlog row image is preferred because minimal or noblob row image can cause errors when a primary key changes in an UPDATE.

Building the Example Tools

The `cmd/` directory contains five example programs: `go-binlogparser` for parsing a binlog file at a given offset, `go-canal` for streaming binlog events to a canal handler, `go-mysqlbinlog` for streaming binlog events directly, `go-mysqldump` for producing a mysqldump-style output in Go, and `go-mysqlserver` for running a fake MySQL server.

The Makefile builds all five:

bash
make build

The compiled binaries land in `bin/`. Running the tests locally requires a MySQL server. The Makefile provides a target that starts one via Docker:

bash
docker run --rm -d --network=host --name go-mysql-server \
	-e MYSQL_ALLOW_EMPTY_PASSWORD=true \
	-e MYSQL_DATABASE=test \
	-v ${PWD}/docker/resources/replication.cnf:/etc/mysql/conf.d/replication.cnf \
	mysql:$(MYSQL_VERSION)

After the server is ready, the test suite runs with:

bash
${GO} test -race -v -timeout 2m ./...

The Makefile also includes a `mariadb-start` target that starts a MariaDB container with SSL configured, which covers the MariaDB-specific code paths in the replication package.

MariaDB 11.4 Compatibility and the FillZeroLogPos Option

MariaDB 11.4 introduced an optimization where events written through a transaction or statement cache carry a `LogPos` of zero. This lets MariaDB copy events directly to the binlog without computing the real end position, which improves write performance. For a replication client that needs to track the position of each event inside a transaction, this makes position tracking unreliable.

go-mysql addresses this with the `FillZeroLogPos` configuration option:

go
cfg := replication.BinlogSyncerConfig {
	ServerID: 100,
	Flavor:   "mariadb",
	Host:     "127.0.0.1",
	Port:     3306,
	User:     "root",
	Password: "",
	FillZeroLogPos: true,
}

When `FillZeroLogPos` is true and the flavor is mariadb, the library adds the `BINLOG_SEND_ANNOTATE_ROWS_EVENT` flag to binlog dump commands and dynamically calculates `LogPos` for events with `LogPos=0`. The option has no effect when the flavor is mysql. The README documents that you should set it to true if tracking `LogPos` inside transactions is a requirement. It only applies to the mariadb flavor; setting it for MySQL connections does nothing.

Limitations and Cases Where go-mysql Is the Wrong Tool

go-mysql is not an ORM and does not generate SQL. If your application needs to issue queries, insert records, or manage schema migrations, you want a library that builds on database/sql, such as sqlx or an ORM. go-mysql's client package provides a direct MySQL connection, but it is intended for cases where you need low-level protocol control, not for application-level query building.

The canal component requires ROW format binary logging. If your MySQL server uses STATEMENT or MIXED format, canal will not work correctly. You must set `binlog_format=ROW` in the MySQL configuration before using canal. The Makefile shows the `replication.cnf` volume mount that configures this for the test Docker container, but in a production environment you need to verify this on your actual server.

The library does not currently provide Windows support. The platform support table in the README confirms Linux (amd64, s390x, arm64, arm) and FreeBSD (amd64), but Windows is not listed. FreeBSD is described as sporadically tested by developers rather than covered by CI.

TinyGo is explicitly not supported. The `go.mod` file requires Go 1.25 and imports libraries including `github.com/pingcap/tidb/pkg/parser`, which has its own build requirements that would conflict with TinyGo's subset of the Go standard library.

go-mysql Compared to go-sql-driver/mysql

go-sql-driver/mysql is the standard MySQL driver for Go's database/sql interface. It handles connection pooling, query execution, prepared statements, and result scanning. It is the right choice for the vast majority of Go applications that need to read and write MySQL data through ordinary SQL.

go-mysql does something fundamentally different. Its client package provides raw MySQL protocol access, and its replication package lets Go code subscribe to the binary log stream. These are capabilities that go-sql-driver/mysql does not expose at all, because they are not part of the database/sql contract.

The choice between them is not about performance or correctness in the common case; it is about what the application needs to do. A web application that stores and retrieves user data should use go-sql-driver/mysql with database/sql. A data pipeline that needs to replicate changes from MySQL to another store, or a tool that needs to parse binary log files, should use go-mysql's replication or canal packages.

The two libraries can coexist in the same application. go-mysql also ships its own database/sql-compatible driver package, which can serve as a drop-in alternative if you need access to both the standard SQL interface and the replication capabilities from the same codebase. The `driver` package in go-mysql provides this, though the README does not detail the differences between it and go-sql-driver/mysql.

Editorial conclusion

go-mysql is the correct choice when a Go application needs to read MySQL's binlog stream, sync database changes to an external store, or implement a fake MySQL server for testing. It is not the right tool when your application only needs to run SQL queries: the standard database/sql interface with go-sql-driver/mysql is simpler for that case. Before adopting go-mysql, verify that your MySQL server is configured to use ROW format binary logging, since the canal component requires it. The last push to the repository was on 2026-09-24, and the go.mod requires Go 1.25.

Frequently asked questions

How do I configure go-mysql to read binlog events from a MySQL server?

Create a BinlogSyncerConfig with a unique ServerID, the flavor set to mysql or mariadb, and the connection details. Call NewBinlogSyncer to create the syncer, then call StartSync with the binlog file and position to start receiving events.

Does go-mysql work with MariaDB as well as MySQL?

Yes. Set the Flavor field in BinlogSyncerConfig to mariadb. For MariaDB 11.4 and later, set FillZeroLogPos to true if you need accurate position tracking inside transactions, as MariaDB 11.4 uses a zero LogPos optimization that requires this correction.

What binary log format does the canal package require?

Canal requires ROW format binary logging. The README states that full binlog row image is preferred, because minimal or noblob row image can cause errors when a primary key changes in an UPDATE.

Official sources

  1. go-mysql-org/go-mysql on GitHub
  2. Issues
  3. License: MIT
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/go-mysql-org-go-mysql.svg)](https://hysenlabs.com/projects/go-mysql-org-go-mysql)