diff --git a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss
index e2454336b8..b24f548d60 100644
--- a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss
+++ b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss
@@ -16,11 +16,14 @@ limitations under the License.
 
 .mx_AppearanceUserSettingsTab_fontSlider,
 .mx_AppearanceUserSettingsTab_fontSlider_preview,
-.mx_AppearanceUserSettingsTab_Layout,
-.mx_AppearanceUserSettingsTab .mx_Field {
+.mx_AppearanceUserSettingsTab_Layout {
     @mixin mx_Settings_fullWidthField;
 }
 
+.mx_AppearanceUserSettingsTab .mx_Field {
+    width: 256px;
+}
+
 .mx_AppearanceUserSettingsTab_fontScaling {
     color: $primary-fg-color;
 }
@@ -204,3 +207,14 @@ limitations under the License.
         background-color: rgba($accent-color, 0.08);
     }
 }
+
+.mx_AppearanceUserSettingsTab_Advanced {
+    .mx_AppearanceUserSettingsTab_AdvancedToggle {
+        color: $accent-color;
+        margin-bottom: 16px;
+    }
+
+    .mx_AppearanceUserSettingsTab_systemFont {
+        margin-left: calc($font-16px + 10px);
+    }
+}
diff --git a/src/components/views/elements/Field.tsx b/src/components/views/elements/Field.tsx
index fbee431d6e..834edff7df 100644
--- a/src/components/views/elements/Field.tsx
+++ b/src/components/views/elements/Field.tsx
@@ -54,6 +54,8 @@ interface IProps {
     // If specified, contents will appear as a tooltip on the element and
     // validation feedback tooltips will be suppressed.
     tooltipContent?: React.ReactNode;
+    // If specified the tooltip will be shown regardless of feedback
+    forceTooltipVisible?: boolean;
     // If specified alongside tooltipContent, the class name to apply to the
     // tooltip itself.
     tooltipClassName?: string;
@@ -242,10 +244,9 @@ export default class Field extends React.PureComponent<PropShapes, IState> {
         const Tooltip = sdk.getComponent("elements.Tooltip");
         let fieldTooltip;
         if (tooltipContent || this.state.feedback) {
-            const addlClassName = tooltipClassName ? tooltipClassName : '';
             fieldTooltip = <Tooltip
-                tooltipClassName={`mx_Field_tooltip ${addlClassName}`}
-                visible={this.state.feedbackVisible}
+                tooltipClassName={classNames("mx_Field_tooltip", tooltipClassName)}
+                visible={(this.state.focused && this.props.forceTooltipVisible) || this.state.feedbackVisible}
                 label={tooltipContent || this.state.feedback}
             />;
         }
diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
index 46723ec7cd..e935663bbe 100644
--- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
@@ -21,7 +21,6 @@ import {_t} from "../../../../../languageHandler";
 import SettingsStore, {SettingLevel} from "../../../../../settings/SettingsStore";
 import { enumerateThemes } from "../../../../../theme";
 import ThemeWatcher from "../../../../../settings/watchers/ThemeWatcher";
-import Field from "../../../elements/Field";
 import Slider from "../../../elements/Slider";
 import AccessibleButton from "../../../elements/AccessibleButton";
 import dis from "../../../../../dispatcher/dispatcher";
@@ -32,6 +31,7 @@ import { IValidationResult, IFieldState } from '../../../elements/Validation';
 import StyledRadioButton from '../../../elements/StyledRadioButton';
 import StyledCheckbox from '../../../elements/StyledCheckbox';
 import SettingsFlag from '../../../elements/SettingsFlag';
+import Field from '../../../elements/Field';
 import EventTilePreview from '../../../elements/EventTilePreview';
 
 interface IProps {
@@ -55,6 +55,9 @@ interface IState extends IThemeState {
     customThemeUrl: string;
     customThemeMessage: CustomThemeMessage;
     useCustomFontSize: boolean;
+    useSystemFont: boolean;
+    systemFont: string;
+    showAdvanced: boolean;
     useIRCLayout: boolean;
 }
 
@@ -73,6 +76,9 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
             customThemeUrl: "",
             customThemeMessage: {isError: false, text: ""},
             useCustomFontSize: SettingsStore.getValue("useCustomFontSize"),
+            useSystemFont: SettingsStore.getValue("useSystemFont"),
+            systemFont: SettingsStore.getValue("systemFont"),
+            showAdvanced: false,
             useIRCLayout: SettingsStore.getValue("useIRCLayout"),
         };
     }
@@ -374,6 +380,47 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
         </div>;
     };
 
+    private renderAdvancedSection() {
+        const toggle = <div
+            className="mx_AppearanceUserSettingsTab_AdvancedToggle"
+            onClick={() => this.setState({showAdvanced: !this.state.showAdvanced})}
+        >
+            {this.state.showAdvanced ? "Hide advanced" : "Show advanced"}
+        </div>;
+
+        let advanced: React.ReactNode;
+
+        if (this.state.showAdvanced) {
+            advanced = <div>
+                <SettingsFlag
+                    name="useSystemFont"
+                    level={SettingLevel.DEVICE}
+                    useCheckbox={true}
+                    onChange={(checked) => this.setState({useSystemFont: checked})}
+                />
+                <Field
+                    className="mx_AppearanceUserSettingsTab_systemFont"
+                    label={SettingsStore.getDisplayName("systemFont")}
+                    onChange={(value) => {
+                        this.setState({
+                            systemFont: value.target.value,
+                        });
+
+                        SettingsStore.setValue("systemFont", null, SettingLevel.DEVICE, value.target.value);
+                    }}
+                    tooltipContent="Set the name of a font installed on your system & Riot will attempt to use it."
+                    forceTooltipVisible={true}
+                    disabled={!this.state.useSystemFont}
+                    value={this.state.systemFont}
+                />
+            </div>;
+        }
+        return <div className="mx_SettingsTab_section mx_AppearanceUserSettingsTab_Advanced">
+            {toggle}
+            {advanced}
+        </div>;
+    }
+
     render() {
         return (
             <div className="mx_SettingsTab mx_AppearanceUserSettingsTab">
@@ -384,6 +431,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
                 {this.renderThemeSection()}
                 {SettingsStore.isFeatureEnabled("feature_font_scaling") ? this.renderFontSection() : null}
                 {SettingsStore.isFeatureEnabled("feature_irc_ui") ? this.renderLayoutSection() : null}
+                {this.renderAdvancedSection()}
             </div>
         );
     }
diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts
index 5f7ca1293c..379a0a4451 100644
--- a/src/dispatcher/actions.ts
+++ b/src/dispatcher/actions.ts
@@ -69,4 +69,14 @@ export enum Action {
      * Opens the user menu (previously known as the top left menu). No additional payload information required.
      */
     ToggleUserMenu = "toggle_user_menu",
+
+    /**
+     * Sets the apps root font size. Should be used with UpdateFontSizePayload
+     */
+    UpdateFontSize = "update_font_size",
+
+    /**
+     * Sets a system font. Should be used with UpdateSystemFontPayload
+     */
+    UpdateSystemFont = "update_system_font",
 }
diff --git a/src/dispatcher/payloads/UpdateFontSizePayload.ts b/src/dispatcher/payloads/UpdateFontSizePayload.ts
new file mode 100644
index 0000000000..6577acd594
--- /dev/null
+++ b/src/dispatcher/payloads/UpdateFontSizePayload.ts
@@ -0,0 +1,27 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+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 { ActionPayload } from "../payloads";
+import { Action } from "../actions";
+
+export interface UpdateFontSizePayload extends ActionPayload {
+    action: Action.UpdateFontSize;
+
+    /**
+     * The font size to set the root to
+     */
+    size: number;
+}
diff --git a/src/dispatcher/payloads/UpdateSystemFontPayload.ts b/src/dispatcher/payloads/UpdateSystemFontPayload.ts
new file mode 100644
index 0000000000..aa59db5aa9
--- /dev/null
+++ b/src/dispatcher/payloads/UpdateSystemFontPayload.ts
@@ -0,0 +1,32 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+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 { ActionPayload } from "../payloads";
+import { Action } from "../actions";
+
+export interface UpdateSystemFontPayload extends ActionPayload {
+    action: Action.UpdateSystemFont;
+
+    /**
+     * Specify whether to use a system font or the stylesheet font
+     */
+    useSystemFont: boolean;
+
+    /**
+     * The system font to use
+     */
+    font: string;
+}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 646f43af33..9982578506 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -460,6 +460,8 @@
     "Mirror local video feed": "Mirror local video feed",
     "Enable Community Filter Panel": "Enable Community Filter Panel",
     "Match system theme": "Match system theme",
+    "Use a system font": "Use a system font",
+    "System font name": "System font name",
     "Allow Peer-to-Peer for 1:1 calls": "Allow Peer-to-Peer for 1:1 calls",
     "Send analytics data": "Send analytics data",
     "Never send encrypted messages to unverified sessions from this session": "Never send encrypted messages to unverified sessions from this session",
diff --git a/src/settings/Settings.js b/src/settings/Settings.js
index 028f355ab8..eb882b2d18 100644
--- a/src/settings/Settings.js
+++ b/src/settings/Settings.js
@@ -30,6 +30,8 @@ import PushToMatrixClientController from './controllers/PushToMatrixClientContro
 import ReloadOnChangeController from "./controllers/ReloadOnChangeController";
 import {RIGHT_PANEL_PHASES} from "../stores/RightPanelStorePhases";
 import FontSizeController from './controllers/FontSizeController';
+import SystemFontController from './controllers/SystemFontController';
+import UseSystemFontController from './controllers/UseSystemFontController';
 
 // These are just a bunch of helper arrays to avoid copy/pasting a bunch of times
 const LEVELS_ROOM_SETTINGS = ['device', 'room-device', 'room-account', 'account', 'config'];
@@ -319,6 +321,18 @@ export const SETTINGS = {
         default: true,
         displayName: _td("Match system theme"),
     },
+    "useSystemFont": {
+        supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
+        default: false,
+        displayName: _td("Use a system font"),
+        controller: new UseSystemFontController(),
+    },
+    "systemFont": {
+        supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
+        default: "",
+        displayName: _td("System font name"),
+        controller: new SystemFontController(),
+    },
     "webRtcAllowPeerToPeer": {
         supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
         displayName: _td('Allow Peer-to-Peer for 1:1 calls'),
diff --git a/src/settings/controllers/FontSizeController.js b/src/settings/controllers/FontSizeController.ts
similarity index 80%
rename from src/settings/controllers/FontSizeController.js
rename to src/settings/controllers/FontSizeController.ts
index 3ef01ab99b..6440fd32fe 100644
--- a/src/settings/controllers/FontSizeController.js
+++ b/src/settings/controllers/FontSizeController.ts
@@ -16,6 +16,8 @@ limitations under the License.
 
 import SettingController from "./SettingController";
 import dis from "../../dispatcher/dispatcher";
+import { UpdateFontSizePayload } from "../../dispatcher/payloads/UpdateFontSizePayload";
+import { Action } from "../../dispatcher/actions";
 
 export default class FontSizeController extends SettingController {
     constructor() {
@@ -24,8 +26,8 @@ export default class FontSizeController extends SettingController {
 
     onChange(level, roomId, newValue) {
         // Dispatch font size change so that everything open responds to the change.
-        dis.dispatch({
-            action: "update-font-size",
+        dis.dispatch<UpdateFontSizePayload>({
+            action: Action.UpdateFontSize,
             size: newValue,
         });
     }
diff --git a/src/settings/controllers/SystemFontController.ts b/src/settings/controllers/SystemFontController.ts
new file mode 100644
index 0000000000..4f591efc17
--- /dev/null
+++ b/src/settings/controllers/SystemFontController.ts
@@ -0,0 +1,36 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+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 SettingsStore from "../SettingsStore";
+import dis from "../../dispatcher/dispatcher";
+import { UpdateSystemFontPayload } from "../../dispatcher/payloads/UpdateSystemFontPayload";
+import { Action } from "../../dispatcher/actions";
+
+export default class SystemFontController extends SettingController {
+    constructor() {
+        super();
+    }
+
+    onChange(level, roomId, newValue) {
+        // Dispatch font size change so that everything open responds to the change.
+        dis.dispatch<UpdateSystemFontPayload>({
+            action: Action.UpdateSystemFont,
+            useSystemFont: SettingsStore.getValue("useSystemFont"),
+            font: newValue,
+        });
+    }
+}
diff --git a/src/settings/controllers/UseSystemFontController.ts b/src/settings/controllers/UseSystemFontController.ts
new file mode 100644
index 0000000000..d598b25962
--- /dev/null
+++ b/src/settings/controllers/UseSystemFontController.ts
@@ -0,0 +1,36 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+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 SettingsStore from "../SettingsStore";
+import dis from "../../dispatcher/dispatcher";
+import { UpdateSystemFontPayload } from "../../dispatcher/payloads/UpdateSystemFontPayload";
+import { Action } from "../../dispatcher/actions";
+
+export default class UseSystemFontController extends SettingController {
+    constructor() {
+        super();
+    }
+
+    onChange(level, roomId, newValue) {
+        // Dispatch font size change so that everything open responds to the change.
+        dis.dispatch<UpdateSystemFontPayload>({
+            action: Action.UpdateSystemFont,
+            useSystemFont: newValue,
+            font: SettingsStore.getValue("systemFont"),
+        });
+    }
+}
diff --git a/src/settings/watchers/FontWatcher.ts b/src/settings/watchers/FontWatcher.ts
index 5527284cd0..9af5156704 100644
--- a/src/settings/watchers/FontWatcher.ts
+++ b/src/settings/watchers/FontWatcher.ts
@@ -18,6 +18,8 @@ import dis from '../../dispatcher/dispatcher';
 import SettingsStore, {SettingLevel} from '../SettingsStore';
 import IWatcher from "./Watcher";
 import { toPx } from '../../utils/units';
+import { Action } from '../../dispatcher/actions';
+import { UpdateSystemFontPayload } from '../../dispatcher/payloads/UpdateSystemFontPayload';
 
 export class FontWatcher implements IWatcher {
     public static readonly MIN_SIZE = 8;
@@ -33,6 +35,10 @@ export class FontWatcher implements IWatcher {
 
     public start() {
         this.setRootFontSize(SettingsStore.getValue("baseFontSize"));
+        this.setSystemFont({
+            useSystemFont: SettingsStore.getValue("useSystemFont"),
+            font: SettingsStore.getValue("systemFont"),
+        });
         this.dispatcherRef = dis.register(this.onAction);
     }
 
@@ -41,8 +47,10 @@ export class FontWatcher implements IWatcher {
     }
 
     private onAction = (payload) => {
-        if (payload.action === 'update-font-size') {
+        if (payload.action === Action.UpdateFontSize) {
             this.setRootFontSize(payload.size);
+        } else if (payload.action === Action.UpdateSystemFont) {
+            this.setSystemFont(payload);
         }
     };
 
@@ -54,4 +62,8 @@ export class FontWatcher implements IWatcher {
         }
         (<HTMLElement>document.querySelector(":root")).style.fontSize = toPx(fontSize);
     };
+
+    private setSystemFont = ({useSystemFont, font}) => {
+        document.body.style.fontFamily = useSystemFont ? font : "";
+    };
 }