I recently helped a customer figure out why a minor version MySQL upgrade was indicating that some tables needed to be rebuilt. The mysql_upgrade program should be run for every upgrade, no matter how big or small the version difference is, but when only the minor version changes, I would normally not expect it to require tables to be rebuilt.

Turns out some of their tables were still marked with an older MySQL version, which could mean a few things… most likely that something went wrong with a previous upgrade, or that the tables were copied from a server with an older version.

In cases like this, did you know there is a fast, safe and simple way to check the version associated with a table? You can do this by reading the FRM file, following the format specification found here.

If you look at that page, you’ll see that the version is 4 bytes long and starts at offset 0x33. Since it is stored in little endian format, you can get the version just by reading the first two bytes.

This means you can use hexdump to read 2 bytes, starting at offset 0x33, and getting the decimal representation of them, to obtain the MySQL version, like so:


telecaster:test fernandoipar$ hexdump -s 0x33 -n 2 -v -d 55_test.frm
0000033 50532
0000035
telecaster:test fernandoipar$ hexdump -s 0x33 -n 2 -v -d 51_test.frm
0000033 50173
0000035

The first example corresponds to a table created on MySQL version 5.5.32, while the second one corresponds to 5.1.73.

Does that mean the 51_test table was created on 5.1.73? Not necessarily, as MySQL will update the version on the FRM whenever the table is rebuilt or altered.

The manual page says the details can change with the transition to the new text based format, but I was able to get the version using this command up to version MySQL 5.7.7.

Hope you found that useful!

9 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Frederic Descamps

Hi Fernando,

Nice post, very interesting to know.

Usually I use dbsake (http://docs.dbsake.net/en/latest/readme.html) to find the version (and more) from the frm:

# dbsake frmdump community_dinner.frm

— Table structure for table community_dinner
— Created with MySQL Version 5.6.22

CREATE TABLE community_dinner (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(20) DEFAULT NULL,
pizzas int(11) DEFAULT NULL,
beers int(11) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Cheers,

Federico Razzoli

Any way to use this trick with MariaDB 10.0? I get this result:

root@ubu1:/var/lib/mysql/my_db# hexdump -s 0x33 -n 2 -v -d country.frm
0000033 34481
0000035

Scott Noyes

mysqlfrm –diagnostic -s t.frm

# Table Statistics:
# Engine : INNODB
# frm Version : 9
# MySQL Version : 5.6.23
# frm File_Version : 5

Chuck Bell

Hello. The mysqlfrm utility does print the version and more when you use the –showstats (-s) option:

mysqlfrm.py –server=… –port=3310 t1.frm -s

# Source on localhost: … connected.
# Starting the spawned server on port 3310 … done.
# Reading .frm files
#
# Reading the t1.frm file.
#
# CREATE statement for ./mysql-test/std_data/frm_files/t1.frm:
#

CREATE TABLE frm_files.t1 (
a int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1

# File Statistics:
# Last Modified : Thu Jul 9 11:20:34 2015
# Creation Time : Thu Jul 9 11:20:34 2015
# Last Accessed : Thu Jul 9 11:20:34 2015
# Mode : 33188
# Size : 8554

# Table Statistics:
# Engine : HEAP
# frm Version : 9
# MySQL Version : 5.6.11
# frm File_Version : 5
# IO_SIZE : 4096
# Def Partition Engine : None

#…done.

You can get even more details if you use the verbosity (-vvv) option.

Federico Razzoli

: Works perfectly. Thanks!!