# dolthub/go-mysql-server: A MySQL Wire Protocol Engine You Point at Your Own Data

> go-mysql-server is a storage agnostic SQL engine and server written in Go. It speaks the MySQL dialect and wire protocol, ships an in-memory backend for tests, and expects you to implement the storage layer yourself.

**dolthub/go-mysql-server** — A MySQL-compatible relational database with a storage agnostic query engine. Implemented in Go.

- Repository: https://github.com/dolthub/go-mysql-server
- Stars: 2,657 · Forks: 281
- Language: Go
- License: Apache-2.0
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/dolthub-go-mysql-server

## The problem go-mysql-server solves: SQL over storage you already have

Most SQL engines assume they own the bytes. go-mysql-server inverts that. The README describes it as a data-source agnostic SQL engine and server which runs queries on data sources you provide, using the MySQL dialect and wire protocol. Parsing, planning, expression evaluation, session handling and the MySQL client protocol live in this repository. Where rows come from is a separate concern, expressed through interfaces you implement.

The README names two primary use cases. The first is a stand-in for MySQL in a Go test environment, using the built-in memory database implementation. The second is providing access to arbitrary data sources with SQL queries by implementing a handful of interfaces. The most complete real-world implementation, per the README, is Dolt, the versioned SQL database from the same organisation.

That framing tells you who this is for. It is for Go engineers who control a data source that is not MySQL (a filesystem format, an object store, an internal service, a columnar file) and want a MySQL-compatible front door on it. It is also for teams who want their integration tests to talk to something that answers on port 3306 without standing up a MySQL container. It is not aimed at people who want a database they can install and run.

## How the engine and the server fit together

The repository splits into recognisable layers. The sql/ directory holds the type system, schema definitions, expression interfaces and session context. The memory/ directory is the in-memory backend. The server/ directory implements the wire protocol and connection handling. engine.go at the top level wires a provider into a query engine, and optgen/ plus enginetest/ cover the optimiser and the test harness. ARCHITECTURE.md and BACKEND.md exist at the root and are the intended references for the boundary between engine and storage.

Data flow follows the usual shape. A client connects over the MySQL protocol, a session is created, a statement arrives, the engine parses and analyses it against the catalog exposed by your provider, the optimiser rewrites the plan, and execution pulls rows through the interfaces your backend implements. The README's own example shows the wiring: a provider is constructed, passed to sqle.NewDefault, and that engine is handed to server.NewServer alongside a session builder.

The dependency list in go.mod shows the boundaries the project chose. It pulls github.com/dolthub/vitess for the MySQL protocol and parser lineage, go.opentelemetry.io/otel for tracing, github.com/cockroachdb/apd/v3 for decimal arithmetic, and github.com/dolthub/go-icu-regex for ICU-compatible regular expressions. The last one matters for builds and is discussed below. There is no embedded key-value store in the dependency list, which is consistent with the claim that storage is your problem.

## Installing go-mysql-server and running the in-memory example

There is no binary to download. The README instructs you to add the module as a dependency from the directory containing your go.mod. The command it gives is:

```bash
go get github.com/dolthub/go-mysql-server@latest
```

After that, the quickest real use is the in-memory server. The README points at _example/main.go and reproduces it. The abbreviated shape is a provider, an engine, and a server config:

```go
pro := createTestDatabase()
engine := sqle.NewDefault(pro)

config := server.Config{
	Protocol: "tcp",
	Address:  fmt.Sprintf("%s:%d", address, port),
}
s, err := server.NewServer(config, engine, sql.NewContext, memory.NewSessionBuilder(pro), nil)
if err != nil {
	panic(err)
}
if err = s.Start(); err != nil {
	panic(err)
}
```

The example declares address as localhost and port as 3306, and the README shows the resulting connection using the standard client:

```bash
mysql --host=localhost --port=3306 --user=root mydb --execute="SELECT * FROM mytable;"
```

The README states that the included MySQL client is used in the example, but any MySQL-compatible client will work. If you see the four rows for Jane Deo, Jane Doe, John Doe and John Doe, the engine, the memory backend and the wire protocol are all working together.

One build detail belongs in this section rather than in a footnote. The README states that go-mysql-server depends on go-icu-regex, which has a Cgo dependency on ICU4C. To build a project that depends on it you need a C/C++ toolchain, Cgo enabled, and libicu-dev or the equivalent installed and available to your C++ toolchain. There is an escape hatch: compiling with -tags=gms_pure_go swaps in a regex implementation based on the Go standard library. The README warns that some tests do not pass with that tag and that it is not recommended for users seeking MySQL compatibility.

## The compatibility promise and where it stops

The README makes a strong claim: with the exception of specific limitations, go-mysql-server is a drop-in replacement for MySQL, and any client library, tool, query, SQL syntax or SQL function that works with MySQL should also work here. It explicitly calls out the MariaDB Java client as supported, and SUPPORTED_CLIENTS.md exists at the root for the client list. When a gap is found, the README asks you to file an issue.

Read that claim carefully. A drop-in replacement is conditional on "using a full database implementation", as the scope section puts it. The engine alone does not make a database. If your backend returns wrong results, or does not implement an interface completely, the compatibility of the SQL layer will not save you. The README also defers the full compatibility documentation to the Dolt docs on SQL support, which means the authoritative list of what is and is not implemented lives outside this repository. That is a real inconvenience: you are evaluating one project and reading another project's documentation to find its limits.

The gms_pure_go build tag is the second boundary. It exists so you can avoid a C toolchain, and the README is direct that it costs you compatibility and that the test suite does not fully pass under it. If your build environment cannot carry Cgo and libicu-dev, you are choosing between a heavier toolchain and a weaker compatibility story. That is a genuine trade-off, not a footnote.

## When go-mysql-server is the wrong tool

The clearest failure mode is expecting persistence. This repository provides an engine and an in-memory backend. The README describes the memory implementation as suitable for use in tests. Nothing in the README suggests it is a durable store. If you need data to survive a process restart, you are implementing that yourself, or you are using Dolt, which the README calls the main production database implementation of this package.

The second case is simpler: if you want a MySQL-compatible database and you do not have a custom data source, this project adds a layer of work with nothing to show for it. Installing MySQL, MariaDB or Postgres and pointing your application at it is less code than implementing backend interfaces.

The third case is subtler. The interfaces are described as "a handful", which sounds small until you map them onto your data model. A backend has to answer questions about schemas, indexes, primary keys, foreign keys and row iteration in a way the optimiser can reason about. If your data source has no notion of an index, the engine cannot invent one, and every query becomes a scan. The README does not document a fallback for that situation, and BACKEND.md is where the real answer lives.

Finally, the Cgo dependency is a deployment constraint. Cross-compiling a Go binary that links against ICU4C is more involved than cross-compiling a pure Go binary. Teams that ship static binaries to minimal containers should weigh that before adopting.

## How it differs from an embedded SQL library or a MySQL driver

The nearest alternative in the Go ecosystem is an embedded SQL engine such as SQLite, reached through a driver. The difference is architectural. SQLite owns its storage format and gives you a file. go-mysql-server owns no storage and gives you a server that speaks MySQL over TCP. If your consumers are MySQL clients, dashboards or ORMs that expect a MySQL endpoint, the wire protocol is the point, and SQLite cannot offer it without a translation layer.

The other alternative people reach for is a MySQL driver plus a real MySQL instance. That gives you full MySQL behaviour, including everything this project lists as a limitation, at the cost of running and operating a server. go-mysql-server trades that operational weight for backend implementation work. Which side of the trade is cheaper depends entirely on whether your data already lives somewhere you cannot move.

The project's own answer to the third option is Dolt. The README positions Dolt as the reference implementation and the production database built on this engine, and the Dolt docs host the SQL compatibility reference. If you want the engine with storage attached, that is the path the maintainers point at. Choosing go-mysql-server directly means you are choosing to be the storage layer.

## Maintenance, releases and the Apache-2.0 licence

The repository is not archived, and the last push was on 2026-09-24. Releases are infrequent and chunky rather than continuous: v0.20.0 on 2025-05-13, v0.19.0 on 2024-12-19, and v0.18.1 on 2024-04-09. That cadence is worth planning around. If you depend on a fix, it may sit on main for months before it appears in a tagged release, so pinning to a commit is a realistic option for teams that need a specific change.

The version numbers are still in the 0.x range, which in Go module semantics means no compatibility promise across minor versions. A jump from v0.19.0 to v0.20.0 can break your build, and your backend implementation is exactly the kind of code that would feel it. Budget for reading the release notes and re-running your own tests on every bump rather than assuming a patch-level upgrade is safe.

The licence is Apache-2.0, which is permissive and includes an explicit patent grant. For most teams that is unremarkable and compatible with commercial use. Two things to check rather than assume: the transitive dependencies carry their own licences, and go.mod shows a long list of them, and if you build with the default Cgo path you are also linking against ICU4C, whose licence is separate from this project's. That is a factual observation about the dependency graph, not legal advice; your own counsel should review the combination you actually ship.

## Conclusion

Adopt go-mysql-server if you need MySQL dialect and wire protocol behaviour over data that already lives somewhere else, or a MySQL stand-in inside Go tests via the memory backend. Do not adopt it expecting a database: it has no durable storage of its own, and the README points to Dolt as the production implementation. Before committing, verify that your C/C++ toolchain and libicu-dev are present, because the default build path pulls in go-icu-regex through Cgo, and check the compatibility limitations in the Dolt SQL support docs for the specific statements you depend on.

## FAQ

### What is go-mysql-server used for?

The README gives two primary use cases: acting as a stand-in for MySQL in a Go test environment using the built-in memory database implementation, and providing access to arbitrary data sources with SQL queries by implementing a handful of interfaces.

### How do I install go-mysql-server?

There is no binary. From the directory containing your go.mod, run go get github.com/dolthub/go-mysql-server@latest, then build against it. Note that the default build path requires a C/C++ toolchain, Cgo enabled, and libicu-dev or the equivalent.

### Is go-mysql-server a drop-in replacement for MySQL?

The README says it is, with the exception of specific limitations, and that any client library, tool, query or SQL function that works with MySQL should also work here. It also notes that a full drop-in database replacement requires a full database implementation, and defers the compatibility details to the Dolt SQL support documentation.

### Does go-mysql-server store my data?

No. It is a storage agnostic engine and server. The included in-memory backend is described as suitable for use in tests, and the README names Dolt as the main production database implementation of the package.

### Can I build go-mysql-server without a C toolchain?

Yes, by compiling with -tags=gms_pure_go, which selects a regex implementation based on the Go standard library instead of go-icu-regex. The README states that some tests do not pass under that tag and that it is not recommended for users seeking MySQL compatibility.

## Sources

- [dolthub/go-mysql-server on GitHub](https://github.com/dolthub/go-mysql-server)
- [Issues](https://github.com/dolthub/go-mysql-server/issues)
- [License: Apache-2.0](https://github.com/dolthub/go-mysql-server/blob/main/LICENSE)
- [README](https://github.com/dolthub/go-mysql-server/blob/main/README.md)
- [Releases](https://github.com/dolthub/go-mysql-server/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/dolthub-go-mysql-server
