diff --git a/keyserver/src/socket/tunnelbroker-socket.js b/keyserver/src/socket/tunnelbroker-socket.js
--- a/keyserver/src/socket/tunnelbroker-socket.js
+++ b/keyserver/src/socket/tunnelbroker-socket.js
@@ -37,7 +37,11 @@
   heartbeatTimeoutID: ?TimeoutID;
   oneTimeKeysPromise: ?Promise<void>;
 
-  constructor(socketURL: string, initMessage: ConnectionInitializationMessage) {
+  constructor(
+    socketURL: string,
+    initMessage: ConnectionInitializationMessage,
+    onClose: () => mixed,
+  ) {
     const socket = new WebSocket(socketURL);
 
     socket.on('open', () => {
@@ -54,6 +58,7 @@
       this.connected = false;
       this.stopHeartbeatTimeout();
       console.error('Connection to Tunnelbroker closed');
+      onClose();
     });
 
     socket.on('error', (error: Error) => {
diff --git a/keyserver/src/socket/tunnelbroker.js b/keyserver/src/socket/tunnelbroker.js
--- a/keyserver/src/socket/tunnelbroker.js
+++ b/keyserver/src/socket/tunnelbroker.js
@@ -1,7 +1,9 @@
 // @flow
 
+import { clientTunnelbrokerSocketReconnectDelay } from 'lib/shared/timeouts.js';
 import type { ConnectionInitializationMessage } from 'lib/types/tunnelbroker/session-types.js';
 import { getCommConfig } from 'lib/utils/comm-config.js';
+import sleep from 'lib/utils/sleep.js';
 
 import TunnelbrokerSocket from './tunnelbroker-socket.js';
 import { type IdentityInfo } from '../user/identity.js';
@@ -43,7 +45,13 @@
     deviceType: 'keyserver',
   };
 
-  new TunnelbrokerSocket(tbConnectionInfo.url, initMessage);
+  const createNewTunnelbrokerSocket = () => {
+    new TunnelbrokerSocket(tbConnectionInfo.url, initMessage, async () => {
+      await sleep(clientTunnelbrokerSocketReconnectDelay);
+      createNewTunnelbrokerSocket();
+    });
+  };
+  createNewTunnelbrokerSocket();
 }
 
 export { createAndMaintainTunnelbrokerWebsocket };
diff --git a/lib/shared/timeouts.js b/lib/shared/timeouts.js
--- a/lib/shared/timeouts.js
+++ b/lib/shared/timeouts.js
@@ -33,10 +33,18 @@
 // client, since the client will assume network issues and close the socket.
 export const serverResponseTimeout = 5000; // in milliseconds
 
+// This controls how long the client waits before trying to reconnect a
+// disconnected keyserver socket.
+export const clientKeyserverSocketReconnectDelay = 2000;
+
 // Time after which the client consider the Tunnelbroker connection
 // as unhealthy and chooses to close the socket.
 export const tunnelbrokerHeartbeatTimeout = 9000; // in milliseconds
 
+// This controls how long the client waits before trying to reconnect a
+// disconnected Tunnelbroker socket.
+export const clientTunnelbrokerSocketReconnectDelay = 3000;
+
 // Time after which the client consider the Identity Search connection
 // as unhealthy and chooses to close the socket.
 export const identitySearchHeartbeatTimeout = 9000; // in milliseconds
diff --git a/lib/socket/socket.react.js b/lib/socket/socket.react.js
--- a/lib/socket/socket.react.js
+++ b/lib/socket/socket.react.js
@@ -26,6 +26,7 @@
   serverRequestSocketTimeout,
   clientRequestVisualTimeout,
   clientRequestSocketTimeout,
+  clientKeyserverSocketReconnectDelay,
 } from '../shared/timeouts.js';
 import {
   recoveryActionSources,
@@ -281,7 +282,7 @@
 
   reconnect: $Call<typeof _throttle, () => void, number> = _throttle(
     () => this.openSocket('reconnecting'),
-    2000,
+    clientKeyserverSocketReconnectDelay,
   );
 
   componentDidMount() {