diff --git a/browserid/lib/db_mysql.js b/browserid/lib/db_mysql.js
index 5533c26bd330a3e021985e8adf213f4fe2d0b87b..9c41b89960541f41993f6d75fa4676129a3ae4c9 100644
--- a/browserid/lib/db_mysql.js
+++ b/browserid/lib/db_mysql.js
@@ -6,7 +6,7 @@
 /*
  * The Schema:
  *
- *    +--- user ------+       +--- email ----+        +----- key ------+
+ *    +--- user ------+       +--- email ----+        +--- pubkey -----+
  *    |*int id        | <-\   |*int id       | <-\    |*int id         |
  *    | string passwd |    \- |*int user     |    \-- |*int email      |
  *    +---------------+       |*string address        | string pubkey  |
@@ -18,7 +18,7 @@
  *    |*string secret          |
  *    | bool new_acct          |
  *    | string existing        |
- *    | string email           |
+ *    |*string email           |
  *    | string pubkey          |
  *    | string passwd          |
  *    | timestamp ts           |
@@ -27,7 +27,8 @@
 
 const
 mysql = require('mysql'),
-secrets = require('./secrets');
+secrets = require('./secrets'),
+logger = require('../../libs/logging.js');
 
 var client = undefined;
 
@@ -35,12 +36,21 @@ var client = undefined;
 var drop_on_close = undefined;
 
 const schemas = [
-  "CREATE TABLE IF NOT EXISTS user   ( id INTEGER PRIMARY KEY, passwd VARCHAR(64) );",
-  "CREATE TABLE IF NOT EXISTS email  ( id INTEGER PRIMARY KEY, user INTEGER, address VARCHAR(255) UNIQUE, INDEX(address) );",
-  "CREATE TABLE IF NOT EXISTS pubkey ( id INTEGER PRIMARY KEY, email INTEGER, content TEXT, expiry INTEGER );",
+  "CREATE TABLE IF NOT EXISTS user   ( id INTEGER AUTO_INCREMENT PRIMARY KEY, passwd VARCHAR(64) );",
+  "CREATE TABLE IF NOT EXISTS email  ( id INTEGER AUTO_INCREMENT PRIMARY KEY, user INTEGER, address VARCHAR(255) UNIQUE, INDEX(address) );",
+  "CREATE TABLE IF NOT EXISTS pubkey ( id INTEGER AUTO_INCREMENT PRIMARY KEY, email INTEGER, content TEXT, expiry DATETIME );",
   "CREATE TABLE IF NOT EXISTS staged ( secret VARCHAR(48) PRIMARY KEY, new_acct BOOL, existing VARCHAR(255), email VARCHAR(255) UNIQUE, INDEX(email), pubkey TEXT, passwd VARCHAR(64), ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP);"
 ];
 
+// log an unexpected database error
+function logUnexpectedError(detail) {
+  // first, get line number of callee
+  var where;
+  try { dne; } catch (e) { where = e.stack.split('\n')[2]; };
+  // now log it!
+  logger.log('db', { type: "unexpected", message: "unexpected database failure", detail: detail, where: where });
+}
+
 // open & create the mysql database
 exports.open = function(cfg, cb) {
   if (client) throw "database is already open!";
@@ -135,14 +145,6 @@ exports.isStaged = function(email, cb) {
   );
 }
 
-exports.emailsBelongToSameAccount = function() {
-  throw "not implemented";
-}
-
-exports.addKeyToEmail = function() {
-  throw "not implemented";
-}
-
 exports.stageUser = function(obj, cb) {
   var secret = secrets.generate(48);
   // overwrite previously staged users
@@ -155,10 +157,6 @@ exports.stageUser = function(obj, cb) {
                });
 }
 
-exports.stageEmail = function() {
-  throw "not implemented";
-}
-
 exports.gotVerificationSecret = function(secret, cb) {
   client.query(
     "SELECT * FROM staged WHERE secret = ?", [ secret ],
@@ -168,26 +166,115 @@ exports.gotVerificationSecret = function(secret, cb) {
       else {
         var o = rows[0];
 
+        function addEmailAndPubkey(userID) {
+          client.query(
+            "INSERT INTO email(user, address) VALUES(?, ?)",
+            [ userID, o.email ],
+            function(err, info) {
+              if (err) { cb(err); return; }
+              addKeyToEmailRecord(info.insertId, o.pubkey, cb);
+            });
+        }
+
         // delete the record
         client.query("DELETE LOW_PRIORITY FROM staged WHERE secret = ?", [ secret ]);
 
-        // XXX: perform add acct or email depending on value of new_acct BOOL
-        console.log(o);
+        if (o.new_acct) {
+          // we're creating a new account, add appropriate entries into user, email, and pubkey.
+          client.query(
+            "INSERT INTO user(passwd) VALUES(?)",
+            [ o.passwd ],
+            function(err, info) {
+              if (err) { cb(err); return; }
+              addEmailAndPubkey(info.insertId);
+            });
+        } else {
+          // we're adding an email address to an existing user account.  add appropriate entries into email and
+          // pubkey
+          client.query(
+            "SELECT user FROM email WHERE address = ?", [ o.existing ],
+            function(err, rows) {
+              if (err) cb(err);
+              else if (rows.length === 0) cb("cannot find email address: " + o.existing);
+              else {
+                addEmailAndPubkey(rows[0].user);
+              }
+            });
+        }
       }
     }
   );
 }
 
-exports.checkAuth = function() {
+exports.emailsBelongToSameAccount = function(lhs, rhs, cb) {
+  client.query(
+    'SELECT COUNT(*) AS n FROM email WHERE address = ? AND user = ( SELECT user FROM email WHERE address = ? );',
+    [ lhs, rhs ],
+    function (err, rows) {
+      if (err) cb(false);
+      else cb(rows.length === 1 && rows[0].n === 1);
+    });
+}
+
+function addKeyToEmailRecord(emailId, pubkey, cb) {
+  client.query(
+    // XXX: 2 weeks is wrong, but then so is keypairs.
+    "INSERT INTO pubkey(email, content, expiry) VALUES(?, ?, DATE_ADD(NOW(), INTERVAL 2 WEEK))",
+    [ emailId, pubkey ],
+    function(err, info) {
+      cb(err);
+    });
+}
+
+exports.addKeyToEmail = function(existing_email, email, pubkey, cb) {
+  // this function will NOT add a new email address to a user record.  The only
+  // way that happens is when a verification secret is provided to us.  Limiting
+  // the code paths that result in us concluding that a user owns an email address
+  // is a Good Thing.
+  exports.emailsBelongToSameAccount(existing_email, email, function(ok) {
+    if (!ok) { cb("authenticated user doesn't have permission to add a public key to " + email); return; }
+
+    // now we know that the user has permission to add a key.
+    client.query(
+      "SELECT id FROM email WHERE address = ?", [ email ],
+      function(err, rows) {
+        if (err) cb(err);
+        else if (rows.length === 0) cb("cannot find email address: " + email);
+        else {
+          addKeyToEmailRecord(rows[0].id, pubkey, cb);
+        }
+      });
+  });
+}
+
+exports.stageEmail = function() {
   throw "not implemented";
 }
 
+exports.checkAuth = function(email, cb) {
+  client.query(
+    'SELECT passwd FROM user WHERE id = ( SELECT user FROM email WHERE address = ? )',
+    [ email ],
+    function (err, rows) {
+      if (err) logUnexpectedError(err);
+      cb((rows && rows.length == 1) ? rows[0].passwd : undefined);
+    });
+}
+
 exports.getSyncResponse = function() {
   throw "not implemented";
 }
 
-exports.pubkeysForEmail = function() {
-  throw "not implemented";
+exports.pubkeysForEmail = function(email, cb) {
+  client.query(
+    'SELECT content FROM pubkey WHERE email = (SELECT id FROM email WHERE address = ?)',
+    [ email ],
+    function (err, rows) {
+      var ar = [ ];
+      if (!err) rows.forEach(function(r) { ar.push(r.content); });
+      else logUnexpectedError(err);
+      cb(ar);
+    });
 }
 
 exports.removeEmail = function() {
diff --git a/libs/logging.js b/libs/logging.js
index c34aaa0c15ad10cd60c1f1c93b3f7968fb02dc0e..1d18ef520ea635ec36a57ed302728a543e37a6a7 100644
--- a/libs/logging.js
+++ b/libs/logging.js
@@ -35,7 +35,7 @@ exports.log = function(category, entry) {
 
   // timestamp
   entry.at = new Date().toUTCString();
-  
+
   // if no logger, go to console (FIXME: do we really want to log to console?)
   LOGGERS[category].info(JSON.stringify(entry));
 };