diff --git a/pool/base.php b/pool/base.php
index a109a23c..66eb014d 100644
--- a/pool/base.php
+++ b/pool/base.php
@@ -259,7 +259,7 @@ function safetext($txt, $len = 1024)
 #
 function dbd($data, $user)
 {
- return "
Web site is currently down";
+ return "
Database is reloading, mining is all OK";
 }
 #
 function dbdown()
diff --git a/src/ckdb.c b/src/ckdb.c
index ac39b470..ecf4af24 100644
--- a/src/ckdb.c
+++ b/src/ckdb.c
@@ -151,6 +151,8 @@ static char *restorefrom;
 // Only accessed in here
 static bool markersummary_auto;
 
+int switch_state = SWITCH_STATE_ALL;
+
 // disallow: '/' '.' '_' and FLDSEP
 const char *userpatt = "^[^/\\._"FLDSEPSTR"]*$";
 const char *mailpatt = "^[A-Za-z0-9_-][A-Za-z0-9_\\.-]*@[A-Za-z0-9][A-Za-z0-9\\.-]*[A-Za-z0-9]$";
diff --git a/src/ckdb.h b/src/ckdb.h
index ecddeebc..6893ecfa 100644
--- a/src/ckdb.h
+++ b/src/ckdb.h
@@ -55,7 +55,7 @@
 
 #define DB_VLOCK "1"
 #define DB_VERSION "1.0.0"
-#define CKDB_VERSION DB_VERSION"-1.023"
+#define CKDB_VERSION DB_VERSION"-1.031"
 
 #define WHERE_FFL " - from %s %s() line %d"
 #define WHERE_FFL_HERE __FILE__, __func__, __LINE__
@@ -81,6 +81,27 @@
 #define TRUE_CHR 'Y'
 #define FALSE_CHR 'N'
 
+/* Set by cmd_setopts() and used by whatever code needs it
+ * It's loaded during startup but set to SWITCH_STATE_ALL if it's missing,
+ *  meaning all switches are active
+ * The idea is that if you need to manually switch code over from one version
+ *  up to the next version at an indeterminate time then you can do that by
+ *  coding a switch_state test and then externally switch the code over via
+ *  the cmd_setopts() socket interface
+ * It's not for coding runtime options into the code since that can be done
+ *  using optioncontrol directly
+ * It's stored in optioncontrol so that it's value is permanent and
+ *  activationdate and activationheight have their values overridden to
+ *  disable using them
+ * N.B. optioncontrol_item_add() intercepts the change by name and updates
+ *	switch_state but ONLY if the DB update succeeds */
+extern int switch_state;
+#define SWITCH_STATE_NAME "SwitchState"
+/* Each switch state must be higher than all previous
+ * so that future states don't undo old changes */
+#define SWITCH_STATE_AUTHWORKERS 1
+#define SWITCH_STATE_ALL 666666
+
 extern char *EMPTY;
 
 extern const char *userpatt;
@@ -1726,6 +1747,7 @@ extern cmp_t cmp_useratts(K_ITEM *a, K_ITEM *b);
 extern K_ITEM *find_useratts(int64_t userid, char *attname);
 extern cmp_t cmp_workers(K_ITEM *a, K_ITEM *b);
 extern K_ITEM *find_workers(int64_t userid, char *workername);
+extern K_ITEM *first_workers(int64_t userid, K_TREE_CTX *ctx);
 extern K_ITEM *new_worker(PGconn *conn, bool update, int64_t userid, char *workername,
 			  char *diffdef, char *idlenotificationenabled,
 			  char *idlenotificationtime, char *by,
diff --git a/src/ckdb_cmd.c b/src/ckdb_cmd.c
index 80b1f9d1..93c42a69 100644
--- a/src/ckdb_cmd.c
+++ b/src/ckdb_cmd.c
@@ -2308,15 +2308,18 @@ static char *cmd_auth_do(PGconn *conn, char *cmd, char *id, char *by,
 				char *code, char *inet, tv_t *cd,
 				K_TREE *trf_root)
 {
+	K_TREE_CTX ctx[1];
 	char reply[1024] = "";
 	size_t siz = sizeof(reply);
 	K_ITEM *i_poolinstance, *i_username, *i_workername, *i_clientid;
-	K_ITEM *i_enonce1, *i_useragent, *i_preauth, *u_item, *oc_item;
+	K_ITEM *i_enonce1, *i_useragent, *i_preauth, *u_item, *oc_item, *w_item;
 	USERS *users = NULL;
 	char *username;
 	WORKERS *workers = NULL;
 	OPTIONCONTROL *optioncontrol;
-	bool ok;
+	size_t len, off;
+	char *buf;
+	bool ok, first;
 
 	LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
 
@@ -2378,18 +2381,51 @@ static char *cmd_auth_do(PGconn *conn, char *cmd, char *id, char *by,
 	if (!ok) {
 		LOGDEBUG("%s() %s.failed.DBE", __func__, id);
 		return strdup("failed.DBE");
-	} else {
-		// Only flag a successful auth
-		ck_wlock(&last_lock);
-		setnow(&last_auth);
-		ck_wunlock(&last_lock);
 	}
+
+	// Only flag a successful auth
+	ck_wlock(&last_lock);
+	setnow(&last_auth);
+	ck_wunlock(&last_lock);
+
+	if (switch_state < SWITCH_STATE_AUTHWORKERS) {
+		snprintf(reply, siz,
+			 "ok.authorise={\"secondaryuserid\":\"%s\","
+			 "\"difficultydefault\":%d}",
+			 users->secondaryuserid, workers->difficultydefault);
+		LOGDEBUG("%s.%s", id, reply);
+		return strdup(reply);
+	}
+
+	APPEND_REALLOC_INIT(buf, off, len);
 	snprintf(reply, siz,
 		 "ok.authorise={\"secondaryuserid\":\"%s\","
-		 "\"difficultydefault\":%d}",
-		 users->secondaryuserid, workers->difficultydefault);
-	LOGDEBUG("%s.%s", id, reply);
-	return strdup(reply);
+		 "\"workers\":[",
+		 users->secondaryuserid);
+	APPEND_REALLOC(buf, off, len, reply);
+	first = true;
+	K_RLOCK(workers_free);
+	w_item = first_workers(users->userid, ctx);
+	DATA_WORKERS_NULL(workers, w_item);
+	while (w_item && workers->userid == users->userid) {
+		if (CURRENT(&(workers->expirydate))) {
+			snprintf(reply, siz,
+				 "%s{\"workername\":\"%s\","
+				 "\"difficultydefault\":%"PRId32"}",
+				 first ? EMPTY : ",",
+				 workers->workername,
+				 workers->difficultydefault);
+			APPEND_REALLOC(buf, off, len, reply);
+			first = false;
+		}
+		w_item = next_in_ktree(ctx);
+		DATA_WORKERS_NULL(workers, w_item);
+	}
+	K_RUNLOCK(workers_free);
+	APPEND_REALLOC(buf, off, len, "]}");
+
+	LOGDEBUG("%s.%s", id, buf);
+	return buf;
 }
 
 static char *cmd_auth(PGconn *conn, char *cmd, char *id,
@@ -2404,13 +2440,16 @@ static char *cmd_addrauth_do(PGconn *conn, char *cmd, char *id, char *by,
 				char *code, char *inet, tv_t *cd,
 				K_TREE *trf_root)
 {
+	K_TREE_CTX ctx[1];
 	char reply[1024] = "";
 	size_t siz = sizeof(reply);
 	K_ITEM *i_poolinstance, *i_username, *i_workername, *i_clientid;
-	K_ITEM *i_enonce1, *i_useragent, *i_preauth;
+	K_ITEM *i_enonce1, *i_useragent, *i_preauth, *w_item;
 	USERS *users = NULL;
 	WORKERS *workers = NULL;
-	bool ok;
+	size_t len, off;
+	char *buf;
+	bool ok, first;
 
 	LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
 
@@ -2456,18 +2495,51 @@ static char *cmd_addrauth_do(PGconn *conn, char *cmd, char *id, char *by,
 	if (!ok) {
 		LOGDEBUG("%s() %s.failed.DBE", __func__, id);
 		return strdup("failed.DBE");
-	} else {
-		// Only flag a successful auth
-		ck_wlock(&last_lock);
-		setnow(&last_auth);
-		ck_wunlock(&last_lock);
 	}
+
+	// Only flag a successful auth
+	ck_wlock(&last_lock);
+	setnow(&last_auth);
+	ck_wunlock(&last_lock);
+
+	if (switch_state < SWITCH_STATE_AUTHWORKERS) {
+		snprintf(reply, siz,
+			 "ok.addrauth={\"secondaryuserid\":\"%s\","
+			 "\"difficultydefault\":%d}",
+			 users->secondaryuserid, workers->difficultydefault);
+		LOGDEBUG("%s.%s", id, reply);
+		return strdup(reply);
+	}
+
+	APPEND_REALLOC_INIT(buf, off, len);
 	snprintf(reply, siz,
 		 "ok.addrauth={\"secondaryuserid\":\"%s\","
-		 "\"difficultydefault\":%d}",
-		 users->secondaryuserid, workers->difficultydefault);
-	LOGDEBUG("%s.%s", id, reply);
-	return strdup(reply);
+		 "\"workers\":[",
+		 users->secondaryuserid);
+	APPEND_REALLOC(buf, off, len, reply);
+	first = true;
+	K_RLOCK(workers_free);
+	w_item = first_workers(users->userid, ctx);
+	DATA_WORKERS_NULL(workers, w_item);
+	while (w_item && workers->userid == users->userid) {
+		if (CURRENT(&(workers->expirydate))) {
+			snprintf(reply, siz,
+				 "%s{\"workername\":\"%s\","
+				 "\"difficultydefault\":%"PRId32"}",
+				 first ? EMPTY : ",",
+				 workers->workername,
+				 workers->difficultydefault);
+			APPEND_REALLOC(buf, off, len, reply);
+			first = false;
+		}
+		w_item = next_in_ktree(ctx);
+		DATA_WORKERS_NULL(workers, w_item);
+	}
+	K_RUNLOCK(workers_free);
+	APPEND_REALLOC(buf, off, len, "]}");
+
+	LOGDEBUG("%s.%s", id, buf);
+	return buf;
 }
 
 static char *cmd_addrauth(PGconn *conn, char *cmd, char *id,
diff --git a/src/ckdb_data.c b/src/ckdb_data.c
index a4227e7e..f1303265 100644
--- a/src/ckdb_data.c
+++ b/src/ckdb_data.c
@@ -1113,6 +1113,26 @@ K_ITEM *find_workers(int64_t userid, char *workername)
 	return find_in_ktree(workers_root, &look, cmp_workers, ctx);
 }
 
+K_ITEM *first_workers(int64_t userid, K_TREE_CTX *ctx)
+{
+	WORKERS workers;
+	K_TREE_CTX ctx0[1];
+	K_ITEM look;
+
+	if (ctx == NULL)
+		ctx = ctx0;
+
+	workers.userid = userid;
+	workers.workername[0] = '\0';
+	workers.expirydate.tv_sec = 0L;
+	workers.expirydate.tv_usec = 0L;
+
+	INIT_WORKERS(&look);
+	look.data = (void *)(&workers);
+	// Caller needs to check userid/expirydate if the result != NULL
+	return find_after_in_ktree(workers_root, &look, cmp_workers, ctx);
+}
+
 K_ITEM *new_worker(PGconn *conn, bool update, int64_t userid, char *workername,
 		   char *diffdef, char *idlenotificationenabled,
 		   char *idlenotificationtime, char *by,
diff --git a/src/ckdb_dbio.c b/src/ckdb_dbio.c
index 91e43fd8..5b3c1544 100644
--- a/src/ckdb_dbio.c
+++ b/src/ckdb_dbio.c
@@ -2183,6 +2183,13 @@ K_ITEM *optioncontrol_item_add(PGconn *conn, K_ITEM *oc_item, tv_t *cd, bool beg
 
 	DATA_OPTIONCONTROL(row, oc_item);
 
+	// Enforce the rule that switch_state isn't date/height controlled
+	if (strcmp(row->optionname, SWITCH_STATE_NAME) == 0) {
+		row->activationdate.tv_sec = date_begin.tv_sec;
+		row->activationdate.tv_usec = date_begin.tv_usec;
+		row->activationheight = OPTIONCONTROL_HEIGHT;
+	}
+
 	INIT_OPTIONCONTROL(&look);
 	look.data = (void *)row;
 	K_RLOCK(optioncontrol_free);
@@ -2282,6 +2289,11 @@ nostart:
 		}
 		optioncontrol_root = add_to_ktree(optioncontrol_root, oc_item, cmp_optioncontrol);
 		k_add_head(optioncontrol_store, oc_item);
+		if (strcmp(row->optionname, SWITCH_STATE_NAME) == 0) {
+			switch_state = atoi(row->optionvalue);
+			LOGWARNING("%s() set switch_state to %d",
+				   __func__, switch_state);
+		}
 	}
 	K_WUNLOCK(optioncontrol_free);
 
@@ -2320,7 +2332,7 @@ K_ITEM *optioncontrol_add(PGconn *conn, char *optionname, char *optionvalue,
 		TXT_TO_INT("activationheight", activationheight,
 			   row->activationheight);
 	} else
-		row->activationheight = 1;
+		row->activationheight = OPTIONCONTROL_HEIGHT;
 
 	HISTORYDATEINIT(row, cd, by, code, inet);
 	HISTORYDATETRANSFER(trf_root, row);
@@ -2406,6 +2418,14 @@ bool optioncontrol_fill(PGconn *conn)
 
 		optioncontrol_root = add_to_ktree(optioncontrol_root, item, cmp_optioncontrol);
 		k_add_head(optioncontrol_store, item);
+
+		// There should only be one CURRENT version of switch_state
+		if (CURRENT(&(row->expirydate)) &&
+		    strcmp(row->optionname, SWITCH_STATE_NAME) == 0) {
+			switch_state = atoi(row->optionvalue);
+			LOGWARNING("%s() set switch_state to %d",
+				   __func__, switch_state);
+		}
 	}
 	if (!ok) {
 		FREENULL(row->optionvalue);
@@ -2418,6 +2438,8 @@ bool optioncontrol_fill(PGconn *conn)
 	if (ok) {
 		LOGDEBUG("%s(): built", __func__);
 		LOGWARNING("%s(): loaded %d optioncontrol records", __func__, n);
+		LOGWARNING("%s() switch_state initially %d",
+			   __func__, switch_state);
 	}
 
 	return ok;