diff --git a/res/css/_components.scss b/res/css/_components.scss
index fe331504f2..c82dedc069 100644
--- a/res/css/_components.scss
+++ b/res/css/_components.scss
@@ -77,7 +77,6 @@
 @import "./views/elements/_Dropdown.scss";
 @import "./views/elements/_EditableItemList.scss";
 @import "./views/elements/_Field.scss";
-@import "./views/elements/_HexVerify.scss";
 @import "./views/elements/_ImageView.scss";
 @import "./views/elements/_InlineSpinner.scss";
 @import "./views/elements/_ManageIntegsButton.scss";
@@ -156,6 +155,7 @@
 @import "./views/settings/tabs/_SecuritySettingsTab.scss";
 @import "./views/settings/tabs/_SettingsTab.scss";
 @import "./views/settings/tabs/_VoiceSettingsTab.scss";
+@import "./views/verification/_VerificationShowSas.scss";
 @import "./views/voip/_CallView.scss";
 @import "./views/voip/_IncomingCallbox.scss";
 @import "./views/voip/_VideoView.scss";
diff --git a/res/css/structures/_CustomRoomTagPanel.scss b/res/css/structures/_CustomRoomTagPanel.scss
index f02421db2c..45961d7be1 100644
--- a/res/css/structures/_CustomRoomTagPanel.scss
+++ b/res/css/structures/_CustomRoomTagPanel.scss
@@ -21,7 +21,11 @@ limitations under the License.
 
 .mx_CustomRoomTagPanel {
     background-color: $tagpanel-bg-color;
-    max-height: 40%;
+    max-height: 40vh;
+}
+
+.mx_CustomRoomTagPanel_scroller {
+    max-height: inherit;
 }
 
 .mx_CustomRoomTagPanel .mx_AccessibleButton {
diff --git a/res/css/views/elements/_HexVerify.scss b/res/css/views/verification/_VerificationShowSas.scss
similarity index 78%
rename from res/css/views/elements/_HexVerify.scss
rename to res/css/views/verification/_VerificationShowSas.scss
index 3f3ee4b7ea..32ccf6b0bb 100644
--- a/res/css/views/elements/_HexVerify.scss
+++ b/res/css/views/verification/_VerificationShowSas.scss
@@ -14,21 +14,9 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-.mx_HexVerify {
+.mx_VerificationShowSas_sas {
     text-align: center;
-}
-
-.mx_HexVerify_pair {
-    display: inline-block;
     font-weight: bold;
     padding-left: 3px;
     padding-right: 3px;
 }
-
-.mx_HexVerify_pair_verified {
-    color: $accent-color;
-}
-
-.mx_HexVerify_pair:hover{
-    color: $accent-color;
-}
diff --git a/src/MatrixClientPeg.js b/src/MatrixClientPeg.js
index 882a913452..f283eb84a5 100644
--- a/src/MatrixClientPeg.js
+++ b/src/MatrixClientPeg.js
@@ -135,14 +135,7 @@ class MatrixClientPeg {
         const opts = utils.deepCopy(this.opts);
         // the react sdk doesn't work without this, so don't allow
         opts.pendingEventOrdering = "detached";
-
-        const LAZY_LOADING_FEATURE = "feature_lazyloading";
-        if (SettingsStore.isFeatureEnabled(LAZY_LOADING_FEATURE)) {
-            const userId = this.matrixClient.credentials.userId;
-            if (phasedRollOutExpiredForUser(userId, LAZY_LOADING_FEATURE, Date.now())) {
-                opts.lazyLoadMembers = true;
-            }
-        }
+        opts.lazyLoadMembers = true;
 
         // Connect the matrix client to the dispatcher
         MatrixActionCreators.start(this.matrixClient);
diff --git a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js
index e5b82baa92..712d8d2b4e 100644
--- a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js
+++ b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js
@@ -19,6 +19,8 @@ import sdk from '../../../../index';
 import MatrixClientPeg from '../../../../MatrixClientPeg';
 import Modal from '../../../../Modal';
 
+import { MatrixClient } from 'matrix-js-sdk';
+
 import { _t } from '../../../../languageHandler';
 
 const RESTORE_TYPE_PASSPHRASE = 0;
@@ -88,7 +90,7 @@ export default React.createClass({
         });
         try {
             const recoverInfo = await MatrixClientPeg.get().restoreKeyBackupWithPassword(
-                this.state.passPhrase, undefined, undefined, this.state.backupInfo.version,
+                this.state.passPhrase, undefined, undefined, this.state.backupInfo,
             );
             this.setState({
                 loading: false,
@@ -107,11 +109,11 @@ export default React.createClass({
         this.setState({
             loading: true,
             restoreError: null,
-            restoreType: RESTORE_TYPE_PASSPHRASE,
+            restoreType: RESTORE_TYPE_RECOVERYKEY,
         });
         try {
             const recoverInfo = await MatrixClientPeg.get().restoreKeyBackupWithRecoveryKey(
-                this.state.recoveryKey, undefined, undefined, this.state.backupInfo.version,
+                this.state.recoveryKey, undefined, undefined, this.state.backupInfo,
             );
             this.setState({
                 loading: false,
@@ -185,32 +187,31 @@ export default React.createClass({
             title = _t("Error");
             content = _t("Unable to load backup status");
         } else if (this.state.restoreError) {
-            title = _t("Error");
-            content = _t("Unable to restore backup");
+            if (this.state.restoreError.errcode === MatrixClient.RESTORE_BACKUP_ERROR_BAD_KEY) {
+                if (this.state.restoreType === RESTORE_TYPE_RECOVERYKEY) {
+                    title = _t("Recovery Key Mismatch");
+                    content = <div>
+                        <p>{_t(
+                            "Backup could not be decrypted with this key: " +
+                            "please verify that you entered the correct recovery key.",
+                        )}</p>
+                    </div>;
+                } else {
+                    title = _t("Incorrect Recovery Passphrase");
+                    content = <div>
+                        <p>{_t(
+                            "Backup could not be decrypted with this passphrase: " +
+                            "please verify that you entered the correct recovery passphrase.",
+                        )}</p>
+                    </div>;
+                }
+            } else {
+                title = _t("Error");
+                content = _t("Unable to restore backup");
+            }
         } else if (this.state.backupInfo === null) {
             title = _t("Error");
             content = _t("No backup found!");
-        } else if (
-            this.state.recoverInfo &&
-            this.state.recoverInfo.imported === 0 &&
-            this.state.recoverInfo.total > 0
-        ) {
-            title = _t("Error Restoring Backup");
-            if (this.state.restoreType === RESTORE_TYPE_RECOVERYKEY) {
-                content = <div>
-                    <p>{_t(
-                        "Backup could not be decrypted with this key: " +
-                        "please verify that you entered the correct recovery key.",
-                    )}</p>
-                </div>;
-            } else {
-                content = <div>
-                    <p>{_t(
-                        "Backup could not be decrypted with this passphrase: " +
-                        "please verify that you entered the correct recovery passphrase.",
-                    )}</p>
-                </div>;
-            }
         } else if (this.state.recoverInfo) {
             title = _t("Backup Restored");
             let failedToDecrypt;
diff --git a/src/components/views/elements/HexVerify.js b/src/components/views/elements/HexVerify.js
deleted file mode 100644
index 86ead3adc1..0000000000
--- a/src/components/views/elements/HexVerify.js
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
-Copyright 2019 New Vector Ltd.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-import React from "react";
-import PropTypes from "prop-types";
-import classnames from 'classnames';
-
-import sdk from '../../../index';
-
-class HexVerifyPair extends React.Component {
-    static propTypes = {
-        text: PropTypes.string.isRequired,
-        index: PropTypes.number,
-        verified: PropTypes.bool,
-        onChange: PropTypes.func.isRequired,
-    }
-
-    _onClick = () => {
-        this.setState({verified: !this.props.verified});
-        this.props.onChange(this.props.index, !this.props.verified);
-    }
-
-    render() {
-        const classNames = {
-            mx_HexVerify_pair: true,
-            mx_HexVerify_pair_verified: this.props.verified,
-        };
-        const AccessibleButton = sdk.getComponent('views.elements.AccessibleButton');
-        return <AccessibleButton className={classnames(classNames)}
-            onClick={this._onClick}
-        >
-            {this.props.text}
-        </AccessibleButton>;
-    }
-}
-
-/*
- * Helps a user verify a hexadecimal code matches one displayed
- * elsewhere (eg. on a different device)
- */
-export default class HexVerify extends React.Component {
-    static propTypes = {
-        text: PropTypes.string.isRequired,
-        onVerifiedStateChange: PropTypes.func,
-    }
-
-    static defaultProps = {
-        onVerifiedStateChange: function() {},
-    }
-
-    constructor(props) {
-        super(props);
-        this.state = {
-            pairsVerified: [],
-        };
-        for (let i = 0; i < props.text.length; i += 2) {
-            this.state.pairsVerified.push(false);
-        }
-    }
-
-    _onPairChange = (index, newVal) => {
-        const oldVerified = this.state.pairsVerified.reduce((acc, val) => {
-            return acc && val;
-        }, true);
-        const newPairsVerified = this.state.pairsVerified.slice(0);
-        newPairsVerified[index] = newVal;
-        const newVerified = newPairsVerified.reduce((acc, val) => {
-            return acc && val;
-        }, true);
-        this.setState({pairsVerified: newPairsVerified});
-        if (oldVerified !== newVerified) {
-            this.props.onVerifiedStateChange(newVerified);
-        }
-    }
-
-    render() {
-        const pairs = [];
-
-        for (let i = 0; i < this.props.text.length / 2; ++i) {
-            pairs.push(<HexVerifyPair key={i} index={i}
-                text={this.props.text.substr(i * 2, 2)}
-                verified={this.state.pairsVerified[i]}
-                onChange={this._onPairChange}
-            />);
-        }
-        return <div className="mx_HexVerify">
-            {pairs}
-        </div>;
-    }
-}
diff --git a/src/components/views/settings/KeyBackupPanel.js b/src/components/views/settings/KeyBackupPanel.js
index 15856a75f3..cbbca42927 100644
--- a/src/components/views/settings/KeyBackupPanel.js
+++ b/src/components/views/settings/KeyBackupPanel.js
@@ -250,19 +250,26 @@ export default class KeyBackupPanel extends React.PureComponent {
                 backupSigStatuses = _t("Backup is not signed by any of your devices");
             }
 
+            let trustedLocally;
+            if (this.state.backupSigStatus.trusted_locally) {
+                trustedLocally = _t("This backup is trusted because it has been restored on this device");
+            }
+
             return <div>
-                {_t("Backup version: ")}{this.state.backupInfo.version}<br />
-                {_t("Algorithm: ")}{this.state.backupInfo.algorithm}<br />
-                {clientBackupStatus}<br />
+                <div>{_t("Backup version: ")}{this.state.backupInfo.version}</div>
+                <div>{_t("Algorithm: ")}{this.state.backupInfo.algorithm}</div>
+                <div>{clientBackupStatus}</div>
                 {uploadStatus}
-                <div>{backupSigStatuses}</div><br />
-                <br />
-                <AccessibleButton kind="primary" onClick={this._restoreBackup}>
-                    { _t("Restore backup") }
-                </AccessibleButton>&nbsp;&nbsp;&nbsp;
-                <AccessibleButton kind="danger" onClick={this._deleteBackup}>
-                    { _t("Delete backup") }
-                </AccessibleButton>
+                <div>{backupSigStatuses}</div>
+                <div>{trustedLocally}</div>
+                <p>
+                    <AccessibleButton kind="primary" onClick={this._restoreBackup}>
+                        { _t("Restore backup") }
+                    </AccessibleButton>&nbsp;&nbsp;&nbsp;
+                    <AccessibleButton kind="danger" onClick={this._deleteBackup}>
+                        { _t("Delete backup") }
+                    </AccessibleButton>
+                </p>
             </div>;
         } else {
             return <div>
diff --git a/src/components/views/settings/tabs/LabsSettingsTab.js b/src/components/views/settings/tabs/LabsSettingsTab.js
index fc64c1bd04..e06f87460b 100644
--- a/src/components/views/settings/tabs/LabsSettingsTab.js
+++ b/src/components/views/settings/tabs/LabsSettingsTab.js
@@ -18,9 +18,7 @@ import React from 'react';
 import {_t} from "../../../../languageHandler";
 import PropTypes from "prop-types";
 import SettingsStore, {SettingLevel} from "../../../../settings/SettingsStore";
-import MatrixClientPeg from "../../../../MatrixClientPeg";
 import LabelledToggleSwitch from "../../elements/LabelledToggleSwitch";
-const Modal = require("../../../../Modal");
 const sdk = require("../../../../index");
 
 export class LabsSettingToggle extends React.Component {
@@ -28,38 +26,7 @@ export class LabsSettingToggle extends React.Component {
         featureId: PropTypes.string.isRequired,
     };
 
-    async _onLazyLoadChanging(enabling) {
-        // don't prevent turning LL off when not supported
-        if (enabling) {
-            const supported = await MatrixClientPeg.get().doesServerSupportLazyLoading();
-            if (!supported) {
-                await new Promise((resolve) => {
-                    const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
-                    Modal.createDialog(QuestionDialog, {
-                        title: _t("Lazy loading members not supported"),
-                        description:
-                            <div>
-                                { _t("Lazy loading is not supported by your " +
-                                    "current homeserver.") }
-                            </div>,
-                        button: _t("OK"),
-                        onFinished: resolve,
-                    });
-                });
-                return false;
-            }
-        }
-        return true;
-    }
-
     _onChange = async (checked) => {
-        if (this.props.featureId === "feature_lazyloading") {
-            const confirmed = await this._onLazyLoadChanging(checked);
-            if (!confirmed) {
-                return;
-            }
-        }
-
         await SettingsStore.setFeatureEnabled(this.props.featureId, checked);
         this.forceUpdate();
     };
diff --git a/src/components/views/verification/VerificationShowSas.js b/src/components/views/verification/VerificationShowSas.js
index 6f3209989e..0224571d9e 100644
--- a/src/components/views/verification/VerificationShowSas.js
+++ b/src/components/views/verification/VerificationShowSas.js
@@ -28,19 +28,11 @@ export default class VerificationShowSas extends React.Component {
 
     constructor() {
         super();
-        this.state = {
-            sasVerified: false,
-        };
-    }
-
-    _onVerifiedStateChange = (newVal) => {
-        this.setState({sasVerified: newVal});
     }
 
     render() {
         const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
-        const HexVerify = sdk.getComponent('views.elements.HexVerify');
-        return <div>
+        return <div className="mx_VerificationShowSas">
             <p>{_t(
                 "Verify this user by confirming the following number appears on their screen.",
             )}</p>
@@ -48,15 +40,11 @@ export default class VerificationShowSas extends React.Component {
                 "For maximum security, we recommend you do this in person or use another " +
                 "trusted means of communication.",
             )}</p>
-            <HexVerify text={this.props.sas}
-                onVerifiedStateChange={this._onVerifiedStateChange}
-            />
-            <p>{_t(
-                "To continue, click on each pair to confirm it's correct.",
-            )}</p>
+            <div className="mx_VerificationShowSas_sas">
+                {this.props.sas}
+            </div>
             <DialogButtons onPrimaryButtonClick={this.props.onDone}
                 primaryButton={_t("Continue")}
-                primaryDisabled={!this.state.sasVerified}
                 hasCancel={true}
                 onCancel={this.props.onCancel}
             />
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index a5b04f1981..d612ae78ef 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -265,7 +265,6 @@
     "Message Pinning": "Message Pinning",
     "Custom user status messages": "Custom user status messages",
     "Group & filter rooms by custom tags (refresh to apply changes)": "Group & filter rooms by custom tags (refresh to apply changes)",
-    "Increase performance by only loading room members on first view": "Increase performance by only loading room members on first view",
     "Backup of encryption keys to server": "Backup of encryption keys to server",
     "Render simple counters in room header": "Render simple counters in room header",
     "Two-way device verification using short text": "Two-way device verification using short text",
@@ -386,6 +385,7 @@
     "Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>": "Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>",
     "Verify...": "Verify...",
     "Backup is not signed by any of your devices": "Backup is not signed by any of your devices",
+    "This backup is trusted because it has been restored on this device": "This backup is trusted because it has been restored on this device",
     "Backup version: ": "Backup version: ",
     "Algorithm: ": "Algorithm: ",
     "Restore backup": "Restore backup",
@@ -477,8 +477,6 @@
     "Identity Server is": "Identity Server is",
     "Access Token:": "Access Token:",
     "click to reveal": "click to reveal",
-    "Lazy loading members not supported": "Lazy loading members not supported",
-    "Lazy loading is not supported by your current homeserver.": "Lazy loading is not supported by your current homeserver.",
     "Labs": "Labs",
     "Notifications": "Notifications",
     "Start automatically after system login": "Start automatically after system login",
@@ -1096,11 +1094,12 @@
     "\"%(RoomName)s\" contains devices that you haven't seen before.": "\"%(RoomName)s\" contains devices that you haven't seen before.",
     "Unknown devices": "Unknown devices",
     "Unable to load backup status": "Unable to load backup status",
+    "Recovery Key Mismatch": "Recovery Key Mismatch",
+    "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.": "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.",
+    "Incorrect Recovery Passphrase": "Incorrect Recovery Passphrase",
+    "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.": "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.",
     "Unable to restore backup": "Unable to restore backup",
     "No backup found!": "No backup found!",
-    "Error Restoring Backup": "Error Restoring Backup",
-    "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.": "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.",
-    "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.": "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.",
     "Backup Restored": "Backup Restored",
     "Failed to decrypt %(failedCount)s sessions!": "Failed to decrypt %(failedCount)s sessions!",
     "Restored %(sessionCount)s session keys": "Restored %(sessionCount)s session keys",
diff --git a/src/settings/Settings.js b/src/settings/Settings.js
index d9363315f5..02c2bad14b 100644
--- a/src/settings/Settings.js
+++ b/src/settings/Settings.js
@@ -21,7 +21,6 @@ import {
     NotificationBodyEnabledController,
     NotificationsEnabledController,
 } from "./controllers/NotificationControllers";
-import LazyLoadingController from "./controllers/LazyLoadingController";
 import CustomStatusController from "./controllers/CustomStatusController";
 
 // These are just a bunch of helper arrays to avoid copy/pasting a bunch of times
@@ -106,13 +105,6 @@ export const SETTINGS = {
         supportedLevels: LEVELS_FEATURE,
         default: false,
     },
-    "feature_lazyloading": {
-        isFeature: true,
-        displayName: _td("Increase performance by only loading room members on first view"),
-        supportedLevels: LEVELS_FEATURE,
-        controller: new LazyLoadingController(),
-        default: true,
-    },
     "feature_keybackup": {
         isFeature: true,
         displayName: _td("Backup of encryption keys to server"),
diff --git a/src/settings/controllers/LazyLoadingController.js b/src/settings/controllers/LazyLoadingController.js
deleted file mode 100644
index 90f095c9ca..0000000000
--- a/src/settings/controllers/LazyLoadingController.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
-Copyright 2018 New Vector
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-import SettingController from "./SettingController";
-import MatrixClientPeg from "../../MatrixClientPeg";
-import PlatformPeg from "../../PlatformPeg";
-
-export default class LazyLoadingController extends SettingController {
-    async onChange(level, roomId, newValue) {
-        if (!PlatformPeg.get()) return;
-
-        MatrixClientPeg.get().stopClient();
-        await MatrixClientPeg.get().store.deleteAllData();
-        PlatformPeg.get().reload();
-    }
-}