diff --git a/server/store/a_store-packr.go b/server/store/a_store-packr.go
index 6e52db0ca8b9226c3887b08a2d5b4809cbf01307..cd3f3619e792f4423f8b05f81a330dd57916692c 100644
--- a/server/store/a_store-packr.go
+++ b/server/store/a_store-packr.go
@@ -7,6 +7,7 @@ import "github.com/gobuffalo/packr"
 // You can use the "packr clean" command to clean up this,
 // and any other packr generated files.
 func init() {
+		packr.PackJSONBytes("migrations", "migrations_test.go", "\"H4sIAAAAAAAA/5xWXW+bSBe+hl9xhPS+gi6FSrtXWfkijd1ud/PRBqfaVRS5Y3OwR4EZcmZwalX+76szgCFpa3V7Y8NwPp7znK+pxeperBEquSZhpVbG92VVa7IQ+l6QCyuWwmBqHsrA94KisvwndSp1Y6U7q4TdpCRUzi/atL9pY5D4sRZ20/+nhSyxPyAsSlw5cxaNlWod+L4XrKXdNMtkpat0rV+ah/JlTnKLlFa7FsMCxjKVsFZ1ktLir4HvtaHgEzFqlqi2HMXL7nPw1JexhHa1odRhKXapMAbJBn7k+0WjVjBHY7MP59LixYGq0MKLDnsyj+CL75lmmUuCkwkEA6B8GQOSOzUPZXJVowpbwRiCkworTbuTIPK91mdyqWdEmkLr1CLfy7FAgnyZnJXaYBj5HjVqDCMG9tHajPz9CPLFLvtwfgyxLECb5C1aVNswuPgn+3C+mM+yeRDBZAJBwDKeTbJ7WYfBpYZBAlBtJWlVobKwFSTFskQOY/+Ehz5vuVH87l6TS3w806qQaw4mNyq5RAsTCOyqbkWT94IMzmWFMAFLDbanp3lOMPk24sUfVwy7VzfmMf+u6PvTLGPRJoYFo+JqTc4aIlSWIckCmKYbgxSDvmcRbZJzre+bevbM1k02uw6i31mMuWLvrMe4OxO+twcsDT7/3rgHJSp0pB2rE9Z6o6kSdppdhtH3i8X3SOWOaHGP4e3dcmcxht+4ZoTKk2sUeUgqjzhHRSE/s2hR2SSrSSpbhMHif5+DGIwlqdZOMvK9RQtswjU4+4yrMDi7np3OZzA9nZ++Ps1mo/mx4KgD+AVa+0fK+murNz9p6Wg7eAfz0+ur9wPkd29g9ve7bJ4ddTnqur6vnnkbdRQ7hhecvOnrGHJJuLKadh2brt8qJvz/3RBK3shymCeZbmiFXCNTSSeDeuyqg2enORRIP0mTt6Vehu7pTy1VOChB8CLhzuP8pSl8RJLFDuxGWLAbJARpQFgoURgLWo1WAFjNMY7otrOqtjsm1qE4kolnnjqbag1NDY+a7o3vqUMQPQsuO5yyEfoqPny+qQeH56gOMGJQP45EcD0YfGh4WlGjYCMMKD1efD2ynwI2e2hEyd5f/SdYhFskwwQNQJ4R9cNwpvpRHWFq7/tp6pZCx0hZjnLem5RoYKWVFVJxnYARFYJBC7oYQ3Rmk9GekWv3ZdojO9PKorLf2Dg870w7oerbtjPubu/ahy9731t1mocyaa8abnRNJYVBcmxXFppgEYNkRRJqjdDbc9NXFiCTd4btODCe1+2poYVkcikqDKOhg1is43HxdfO1Q8bzLMmqQjd7x+F4PaRigOSMte4PahMQdY0qD7uDeHDzWhgMi8h5cRYdhbc90Du3Ip2S7wT2rsxuDLq+RmVpBwXpyiX0k1P+xOyDMCCA+HaBaoXAQLkqWEzzkDAJzx0ylqG3TrtrW/JRlA1eFaE7jZILUf+FOxNGt6/ukqxdHtHdIR3bIfY2/Rz7uHOcOdMWLBkbw9ZdJPb+vwEAAP//wureGqEKAAA=\"")
 		packr.PackJSONBytes("migrations", "mysql/20180626224600_create_issued_certs.sql", "\"H4sIAAAAAAAA/5SR0UrDMBSG7/MUh92swxVSYYjuqtoMirUbXQsbIk1oDhrqupLGrX17aV21TkGEXIXv//nOObYNFzv1rIVBSEpyFzE3ZhC7twEDfwHhMga28dfxGriqqjeUaYbaVBwsAsBzbFIlORyEzl6Eti5ns0mXCZMgmLZEqVWRqVK8VmeUxxZuEsQwenwadWSmURiUqTAcpDBo1A4/qbFzfUVt6tjUAUpv2ueMuxjWpdJY/Tem8bDPUXIwqmhUYSznS4l+EOKY5thwMFib9mcV+Q9utIV7tgWrH31CJvN+a37osQ1wJet0aLUMf+xuaP1r/qT3Z08/xhTOKsnwsN7+WBAvWq5Oh/1eMyfvAQAA//+OXEmHBQIAAA==\"")
 		packr.PackJSONBytes("migrations", "sqlite3/20180626224600_create_issued_certs.sql", "\"H4sIAAAAAAAA/5SR0UrDMBSG7/MUh92swxVSYYjuqtoMirUbXQsbIk1oDhrqupLGrX17aV21TkGEXIXv//nOObYNFzv1rIVBSEpyFzE3ZhC7twEDfwHhMga28dfxGriqqjeUaYbaVBwsAsBzbFIlORyEzl6Eti5ns0mXCZMgmLZEqVWRqVK8VmeUxxZuEsQwenwadWSmURiUqTAcpDBo1A4/qbFzfUVt6tjUAUpv2ueMuxjWpdJY/Tem8bDPUXIwqmhUYSznS4l+EOKY5thwMFib9mcV+Q9utIV7tgWrH31CJvN+a37osQ1wJet0aLUMf+xuaP1r/qT3Z08/xhTOKsnwsN7+WBAvWq5Oh/1eMyfvAQAA//+OXEmHBQIAAA==\"")
 }
diff --git a/server/store/migrations/migrations_test.go b/server/store/migrations/migrations_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..ad2259b907b563438258aa7794f81d2df11d5394
--- /dev/null
+++ b/server/store/migrations/migrations_test.go
@@ -0,0 +1,102 @@
+package migrations
+
+import (
+	"database/sql"
+	"fmt"
+	"io/ioutil"
+	"math/rand"
+	"os"
+	"os/user"
+	"path"
+	"path/filepath"
+	"reflect"
+	"testing"
+
+	"github.com/go-sql-driver/mysql"
+	_ "github.com/mattn/go-sqlite3"
+	migrate "github.com/rubenv/sql-migrate"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestSQLiteMigrations(t *testing.T) {
+	subdir := "sqlite3"
+	db, err := sql.Open(subdir, ":memory:")
+	assert.NoError(t, err)
+	defer db.Close()
+	runMigrations(t, db, subdir)
+}
+
+func TestMySQLMigrations(t *testing.T) {
+	if os.Getenv("MYSQL_TEST") == "" {
+		t.Skip("No MYSQL_TEST environment variable")
+	}
+	subdir := "mysql"
+	dsn := mysql.NewConfig()
+	dsn.Net = "tcp"
+	dsn.ParseTime = true
+	dsn.Addr = os.Getenv("MYSQL_TEST_HOST")
+	dsn.Passwd = os.Getenv("MYSQL_TEST_PASS")
+	u, _ := user.Current()
+	if testUser, ok := os.LookupEnv("MYSQL_TEST_USER"); ok {
+		dsn.User = testUser
+	} else {
+		dsn.User = u.Username
+	}
+	db, err := sql.Open(subdir, dsn.FormatDSN())
+	assert.NoError(t, err)
+
+	rnd := make([]byte, 4)
+	rand.Read(rnd)
+	suffix := fmt.Sprintf("_%x", string(rnd))
+	_, err = db.Exec("CREATE DATABASE migrations_test" + suffix)
+	assert.NoError(t, err)
+	_, err = db.Exec("USE migrations_test" + suffix)
+	assert.NoError(t, err)
+	runMigrations(t, db, subdir)
+	db.Exec("DROP DATABASE IF EXISTS migrations_test" + suffix)
+	db.Close()
+}
+
+func runMigrations(t *testing.T, db *sql.DB, directory string) {
+	m := &migrate.FileMigrationSource{
+		Dir: directory,
+	}
+	files, err := filepath.Glob(path.Join(directory, "*.sql"))
+	// Verify that there is at least one migration to run
+	assert.NotEmpty(t, files)
+	assert.NoError(t, err)
+	// Verify that migrating up works
+	n, err := migrate.Exec(db, directory, m, migrate.Up)
+	assert.Len(t, files, n)
+	assert.NoError(t, err)
+	// Verify that a subsequent run has no migrations
+	n, err = migrate.Exec(db, directory, m, migrate.Up)
+	assert.Equal(t, 0, n)
+	assert.NoError(t, err)
+	// Verify that reversing migrations works
+	n, err = migrate.Exec(db, directory, m, migrate.Down)
+	assert.Len(t, files, n)
+}
+
+// Test that all migration directories contain the same set of migrations files.
+func TestMigationDirectoryContents(t *testing.T) {
+	names := map[string][]string{}
+	contents, err := ioutil.ReadDir(".")
+	assert.NoError(t, err)
+	for _, i := range contents {
+		if i.IsDir() {
+			dir := path.Join(i.Name(), "*.sql")
+			files, _ := filepath.Glob(dir)
+			trimmed := []string{}
+			for _, f := range files {
+				trimmed = append(trimmed, filepath.Base(f))
+			}
+			names[i.Name()] = trimmed
+		}
+	}
+	// Use one entry from the `names` map as a reference for all the others.
+	first := names[reflect.ValueOf(names).MapKeys()[0].String()]
+	for _, v := range names {
+		assert.EqualValues(t, first, v)
+	}
+}