Binary Log Format

MySQL binary logs record all data-modifying events for replication and point-in-time recovery. Unlike InnoDB tablespace files which use big-endian byte order, all integer fields in binary logs are little-endian.

File Structure

Every binlog file begins with a 4-byte magic number followed by a sequence of events:

+-------------------+  byte 0
| Magic: 0xFE 'bin' |  4 bytes
+-------------------+  byte 4
| FORMAT_DESCRIPTION |  First event (always)
+-------------------+
| Event 2            |
+-------------------+
| Event 3            |
+-------------------+
| ...                |
+-------------------+
| ROTATE / STOP      |  Last event (usually)
+-------------------+

The magic bytes \xfebin ([0xfe, 0x62, 0x69, 0x6e]) identify the file as a MySQL binary log.

Common Event Header (19 bytes)

Every event starts with a 19-byte header. All fields are little-endian:

OffsetSizeFieldDescription
04timestampSeconds since Unix epoch when the event was created
41type_codeEvent type identifier (see table below)
54server_idOriginating server's server_id value
94event_lengthTotal event size including header, payload, and checksum
134next_positionAbsolute file offset of the next event
172flagsEvent flags (bit 0 = binlog in use / not cleanly closed)

The next_position field enables sequential scanning: read the header, then seek to next_position for the next event.

Event Types

The type code byte identifies the event kind. Key types for analysis:

CodeNameDescription
2QUERY_EVENTSQL statement execution
4ROTATE_EVENTPoints to the next binlog file
15FORMAT_DESCRIPTION_EVENTBinlog metadata (always first real event)
16XID_EVENTTransaction commit (XA transaction ID)
19TABLE_MAP_EVENTMaps table ID to schema/table name
30WRITE_ROWS_EVENTRow insert (row-based replication)
31UPDATE_ROWS_EVENTRow update (row-based replication)
32DELETE_ROWS_EVENTRow delete (row-based replication)
33GTID_LOG_EVENTGlobal Transaction ID
39PARTIAL_UPDATE_ROWS_EVENTPartial JSON update (MySQL 8.0+)
40TRANSACTION_PAYLOAD_EVENTCompressed transaction (MySQL 8.0.20+)

A complete list of all 41 named event types is defined in src/binlog/constants.rs, derived from MySQL's binlog_event.h.

FORMAT_DESCRIPTION_EVENT

The first event after the magic bytes is always a FORMAT_DESCRIPTION_EVENT (FDE). It describes the binlog format version and the server that created the file:

OffsetSizeFieldDescription
02binlog_versionFormat version (4 for all modern MySQL)
250server_versionNull-padded ASCII server version string
524create_timestampTimestamp when the binlog was created
561header_lengthCommon header length (always 19 for v4)
57Npost_header_lengthsArray of per-event-type post-header sizes

The FDE also implicitly tells the parser whether CRC-32C checksums are present. Since binlog_checksum=CRC32 is the default from MySQL 5.6.6 onward, the parser must handle both cases. inno binlog auto-detects checksum presence by attempting to parse the FDE with and without the trailing 4-byte CRC.

ROTATE_EVENT

A ROTATE_EVENT appears at the end of a binlog file (or during live rotation) and points to the next file in the sequence:

OffsetSizeFieldDescription
08positionStart position in the next binlog file
8NfilenameName of the next binlog file (variable length)

Row-Based Replication Events

Row-based replication (the default since MySQL 5.7.7) records actual row data rather than SQL statements.

TABLE_MAP_EVENT

Before any row events, a TABLE_MAP_EVENT maps a numeric table ID to a database and table name. It includes the column count and column type descriptors, enabling the row events that follow to be decoded.

Row Events (WRITE/UPDATE/DELETE)

Row events reference the table ID from the preceding TABLE_MAP_EVENT and contain:

  • A bitmap of columns present in the row image
  • For UPDATE events: a "before" bitmap and an "after" bitmap
  • The actual row data encoded according to InnoDB's column type rules

Row events use v2 format (types 30-32) in MySQL 5.6+, which supports extra data fields for partial row images.

Event Checksums

Since MySQL 5.6.6, each event ends with a 4-byte CRC-32C checksum (when binlog_checksum=CRC32, which is the default):

[common header: 19 bytes][payload: N bytes][CRC-32C: 4 bytes]

The checksum covers all bytes from the start of the event through the end of the payload (everything except the checksum itself). The event_length field in the header includes the 4-byte checksum.

Byte Order Difference

This is worth emphasizing: binary logs use little-endian byte order for all integer fields. This is the opposite of InnoDB tablespace files, which use big-endian. The src/binlog/ module uses byteorder::LittleEndian throughout, while src/innodb/ uses byteorder::BigEndian.

Inspecting Binary Logs with inno

# Parse a binary log file
inno binlog -f mysql-bin.000001

# Verbose output with event details
inno binlog -f mysql-bin.000001 -v

# JSON output
inno binlog -f mysql-bin.000001 --json

Source Reference

  • Constants and event codes: src/binlog/constants.rs
  • Event types and common header: src/binlog/event.rs -- BinlogEventType, CommonEventHeader
  • FDE and ROTATE parsing: src/binlog/header.rs -- FormatDescriptionEvent, RotateEvent
  • Checksum validation: src/binlog/checksum.rs
  • File reader and iteration: src/binlog/file.rs -- BinlogFile
  • MySQL source: libbinlogevents/include/binlog_event.h, sql/binlog/event/event_reader.cpp