diff --git a/keyserver/src/database/migration-config.js b/keyserver/src/database/migration-config.js
--- a/keyserver/src/database/migration-config.js
+++ b/keyserver/src/database/migration-config.js
@@ -12,11 +12,12 @@
 import { createScriptViewer } from '../session/scripts.js';
 import { updateRolesAndPermissionsForAllThreads } from '../updaters/thread-permission-updaters.js';
 import { updateThread } from '../updaters/thread-updaters.js';
+import { ensureUserCredentials } from '../user/checks.js';
 import { createPickledOlmAccount } from '../utils/olm-utils.js';
 
 const botViewer = createScriptViewer(bots.commbot.userID);
 
-const migrations: $ReadOnlyMap<number, () => Promise<void>> = new Map([
+const migrations: $ReadOnlyMap<number, () => Promise<mixed>> = new Map([
   [
     0,
     async () => {
@@ -466,6 +467,18 @@
       }
     },
   ],
+  [39, ensureUserCredentials],
+  [
+    40,
+    // Tokens from identity service are 512 characters long
+    () =>
+      dbQuery(
+        SQL`
+          ALTER TABLE metadata
+          MODIFY COLUMN data VARCHAR(1023)
+        `,
+      ),
+  ],
 ]);
 const newDatabaseVersion: number = Math.max(...migrations.keys());
 
diff --git a/keyserver/src/database/setup-db.js b/keyserver/src/database/setup-db.js
--- a/keyserver/src/database/setup-db.js
+++ b/keyserver/src/database/setup-db.js
@@ -16,8 +16,10 @@
   createOlmAccounts,
 } from '../database/migration-config.js';
 import { createScriptViewer } from '../session/scripts.js';
+import { ensureUserCredentials } from '../user/checks.js';
 
 async function setupDB() {
+  await ensureUserCredentials();
   await createTables();
   await createUsers();
   await createThreads();
@@ -232,7 +234,7 @@
 
       CREATE TABLE metadata (
         name varchar(255) NOT NULL,
-        data varchar(255)
+        data varchar(1023)
       ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
       
       CREATE TABLE policy_acknowledgments (
diff --git a/keyserver/src/user/checks.js b/keyserver/src/user/checks.js
new file mode 100644
--- /dev/null
+++ b/keyserver/src/user/checks.js
@@ -0,0 +1,31 @@
+// @flow
+
+import { getCommConfig } from 'lib/utils/comm-config.js';
+type UserCredentials = { +username: string, +password: string };
+
+async function ensureUserCredentials() {
+  const userCredentials = await getCommConfig<UserCredentials>({
+    folder: 'secrets',
+    name: 'user_credentials',
+  });
+
+  if (!userCredentials) {
+    console.warn(
+      'User credentials for the keyserver owner must be specified. They can be ' +
+        'specified either by setting the ' +
+        '`COMM_JSONCONFIG_secrets_user_credentials` environmental variable, or by ' +
+        'setting a file at keyserver/secrets/user_credentials.json. The contents ' +
+        'should be a JSON blob that looks like this:\n' +
+        '{\n' +
+        '  "username": <user>,\n' +
+        '  "password": <pass>\n' +
+        '}\n',
+    );
+
+    // Since we don't want to apply the migration until there are credentials;
+    // throw the error and force keyserver to be configured next restart
+    throw new Error('missing_keyserver_owner_credentials');
+  }
+}
+
+export { ensureUserCredentials };