Save, restore and copy MySQL accounts and privileges (mysqldumpgrants)

I just stumbled across a post on the forums where somebody asked for a good way to copy MySQL grants between two servers. Since about two years I mostly use a little Perl script mysqldumpgrants I've written back then for such and other related tasks. The post on the forums was still unanswered after almost three months, so I thought it might be helpful to release this little script albeit its simplicity.

When you call mysqldumpgrants without any arguments it will look up the connection information (host, port, user and password) in your .my.cnf file (of course you can also specify them on the command line, in the same way as for the other mysql command line tools), connect to the server and write all the grant statements (plus some comments) to standard output, like so:

-- Grants for pattern %@% extracted by /root/bin/mysqldumpgrants
-- 2006-04-18 16:30:15 (MySQL 5.0.20-standard-log)

-- jobs@%
GRANT USAGE ON *.* TO 'jobs'@'%' IDENTIFIED BY PASSWORD 'xxx';
GRANT SELECT, INSERT, UPDATE, DELETE, LOCK TABLES, EXECUTE
    ON `jobs`.* TO 'jobs'@'%';

...

I usually extract such a file together with my backups. You never know when you might need it (and I prefer the GRANT/REVOKE statements to dealing directly with the user tables).

mysqldumpgrants > grants.sql

It also allows me to quickly hook up a text editor, change something and feed that part back to MySQL.

vi/emacs grants.sql
mysql < grants.sql

And for the original question: Of course you can just pipe the output of mysqldumpgrants to a mysql command line client to copy the grants to another server:

mysqldumpgrants | mysql -h remote.host -u remote.user -p

Let me just give you the relevant sections of the perldoc for a complete overview of the few options:

SYNOPSIS
      mysqldumpgrants [options] [user_pattern[@host_pattern]]
DESCRIPTION
      mysqldumpgrants dumps the grants of a MySQL database as
      valid SQL commands.

      mysqldumpgrants reads the user, password, host and port
      settings from your .my.cnf file by default. These settings
      can be overriden with the options provided on the command
      line.

      The optional argument user_pattern[@host_pattern] controls
      which accounts should be dumped (defaults to all). You can
      use the usual MySQL wildcards _ and %.

      You can redirect the output of mysqldumpgrants to a file
      to backup your user accounts or to easily edit them in a
      text editor or you can pipe it to the mysql command line
      client to copy them directly to another server, like so:

        mysqldumpgrants -h mysql1 a% | mysql -h mysql2

      This would copy all the user accounts starting with the
      letter 'a' from host mysql1 to mysql2 (given both servers
      use the same credentials for login and those are stored in
      a .my.cnf file).
OPTIONS
      -u, --user=#
          user for database login

      -p, --password
          ask for password (you can't provide a password on the
          command line for security reasons, use a .my.cnf file
          instead)

      -h, --host=#
          hostname of database server to connect to

      -P, --port=#
          port to use when connecting to database server

      -d, --drop-user
          adds a DROP USER command for every dumped user just
          before the GRANT commands

      -?, --help
          display this help page

The --drop-user (or -d) option comes in handy if you want to make sure that previous grants with the same user/host combination get really overwritten and not just combined. This will only work with MySQL 5.0 or above (before you had to revoke all the grants manually). The rest of the script should work fine with older releases (of course, as it was written back in 2004), you just have to pay attention if you try to load privileges from a newer server into an older release as some of the privileges might not yet be supported.

It's a simple script, but I use it almost every week, and actually I think this feature should be added to mysqldump (or has it been added already and I just missed it because I used my own script all the time?).

And in case you have to work on a server with a broken Perl DBI/DBD::mysql installation as I had to recently, you can use mysqldumpgrants.sh, a tiny shell script, as a simple replacement:

#/bin/sh
while read GRANT
  do
  echo "-- $GRANT"
  mysql --skip-column-names -Be "SHOW GRANTS FOR $GRANT" | sed 's/$/;/'
  echo
done <<< "`mysql --skip-column-names -Be \
\"SELECT CONCAT('''', user, '''@''', host, '''') FROM mysql.user ORDER BY user, host\"`"