diff --git a/renderer/components/Settings/Security/ChangePasswordDialog.js b/renderer/components/Settings/Security/ChangePasswordDialog.js
index 9ba5af6dae5..9c1df26e3a4 100644
--- a/renderer/components/Settings/Security/ChangePasswordDialog.js
+++ b/renderer/components/Settings/Security/ChangePasswordDialog.js
@@ -11,7 +11,7 @@ const DialogWrapper = ({ loginError, clearLoginError, isOpen, onChange, onCancel
   const formApiRef = useRef(null)
   useEffect(() => {
     const { current: formApi } = formApiRef
-    if (loginError) {
+    if (loginError && formApi) {
       formApi.setFormError(loginError)
       clearLoginError()
     }
diff --git a/renderer/components/Settings/Security/PasswordPromptDialog.js b/renderer/components/Settings/Security/PasswordPromptDialog.js
index 70a0b262984..6bc28b19ece 100644
--- a/renderer/components/Settings/Security/PasswordPromptDialog.js
+++ b/renderer/components/Settings/Security/PasswordPromptDialog.js
@@ -1,13 +1,22 @@
-import React from 'react'
+import React, { useEffect, useRef } from 'react'
 import PropTypes from 'prop-types'
 import { Flex } from 'rebass/styled-components'
 import { FormattedMessage, useIntl } from 'react-intl'
-import { Dialog, Heading, Button, DialogOverlay } from 'components/UI'
+import { Dialog, Heading, Button, DialogOverlay, Message } from 'components/UI'
 import { PasswordInput, Form } from 'components/Form'
 import messages from './messages'
 
-const DialogWrapper = ({ isOpen, onOk, onCancel, isPromptMode }) => {
+const DialogWrapper = ({ loginError, clearLoginError, isOpen, onOk, onCancel, isPromptMode }) => {
   const intl = useIntl()
+  const formApiRef = useRef(null)
+  useEffect(() => {
+    const { current: formApi } = formApiRef
+    if (loginError && formApi) {
+      formApi.setFormError(loginError)
+      clearLoginError()
+    }
+  }, [loginError, clearLoginError])
+
   if (!isOpen) {
     return null
   }
@@ -43,20 +52,32 @@ const DialogWrapper = ({ isOpen, onOk, onCancel, isPromptMode }) => {
 
   return (
     <DialogOverlay alignItems="center" justifyContent="center" position="fixed">
-      <Form onSubmit={handleSubmit}>
-        <Dialog buttons={buttons} header={header} onClose={onCancel} width={640}>
-          <Flex alignItems="center" flexDirection="column" width={350}>
-            <PasswordInput
-              description={intl.formatMessage(inputDesc)}
-              field="password"
-              hasMessageSpacer
-              isRequired
-              minLength={6}
-              width={1}
-              willAutoFocus
-            />
-          </Flex>
-        </Dialog>
+      <Form getApi={api => (formApiRef.current = api)} onSubmit={handleSubmit}>
+        {({ formState: { submits, error } }) => {
+          const willValidateInline = submits > 0
+          return (
+            <Dialog buttons={buttons} header={header} onClose={onCancel} width={640}>
+              {error && (
+                <Message mb={3} variant="error">
+                  {error}
+                </Message>
+              )}
+              <Flex alignItems="center" flexDirection="column" width={350}>
+                <PasswordInput
+                  description={intl.formatMessage(inputDesc)}
+                  field="password"
+                  hasMessageSpacer
+                  isRequired
+                  minLength={6}
+                  validateOnBlur={willValidateInline}
+                  validateOnChange={willValidateInline}
+                  width={1}
+                  willAutoFocus
+                />
+              </Flex>
+            </Dialog>
+          )
+        }}
       </Form>
     </DialogOverlay>
   )
@@ -67,9 +88,11 @@ DialogWrapper.defaultProps = {
 }
 
 DialogWrapper.propTypes = {
+  clearLoginError: PropTypes.func.isRequired,
   isOpen: PropTypes.bool.isRequired,
   isPromptMode: PropTypes.bool,
   isRestoreMode: PropTypes.bool,
+  loginError: PropTypes.string,
   onCancel: PropTypes.func.isRequired,
   onOk: PropTypes.func.isRequired,
 }
diff --git a/renderer/components/Settings/SettingsFieldsSecurity.js b/renderer/components/Settings/SettingsFieldsSecurity.js
index a7aa3927d2c..865cb18bcbe 100644
--- a/renderer/components/Settings/SettingsFieldsSecurity.js
+++ b/renderer/components/Settings/SettingsFieldsSecurity.js
@@ -1,48 +1,38 @@
 import React from 'react'
 import PropTypes from 'prop-types'
-import { useFieldState, useFormState } from 'informed'
-import { useIntl } from 'react-intl'
 import { DataRow } from 'components/UI'
-import { PasswordInput, FieldLabelFactory, Toggle } from 'components/Form'
+import { FieldLabelFactory } from 'components/Form'
 import messages from './messages'
+import PasswordState from './Security/PasswordState'
 
 const FieldLabel = FieldLabelFactory(messages)
 
-const SettingsFieldsSecurity = ({ currentConfig }) => {
-  const { value: isPasswordActive } = useFieldState('password.active')
-  const { submits } = useFormState()
-  const willValidateInline = submits > 0
-  const intl = useIntl()
-
+const SettingsFieldsSecurity = ({
+  currentConfig,
+  changePassword,
+  enablePassword,
+  disablePassword,
+}) => {
   return (
-    <>
-      <DataRow
-        left={<FieldLabel itemKey="password.active" tooltip="password_tooltip" />}
-        right={<Toggle field="password.active" initialValue={currentConfig.password.active} />}
-      />
-      {isPasswordActive && (
-        <DataRow
-          pt={0}
-          right={
-            <PasswordInput
-              description={intl.formatMessage({ ...messages.password_value_description })}
-              field="password.value"
-              initialValue={currentConfig.password.value}
-              isRequired
-              minLength={6}
-              validateOnBlur={willValidateInline}
-              validateOnChange={willValidateInline}
-              width={200}
-            />
-          }
+    <DataRow
+      left={<FieldLabel itemKey="password.active" tooltip="password_tooltip" />}
+      right={
+        <PasswordState
+          onChange={changePassword}
+          onDisable={disablePassword}
+          onEnable={enablePassword}
+          value={currentConfig.password.active}
         />
-      )}
-    </>
+      }
+    />
   )
 }
 
 SettingsFieldsSecurity.propTypes = {
+  changePassword: PropTypes.func.isRequired,
   currentConfig: PropTypes.object.isRequired,
+  disablePassword: PropTypes.func.isRequired,
+  enablePassword: PropTypes.func.isRequired,
 }
 
 export default SettingsFieldsSecurity
diff --git a/renderer/components/Settings/SettingsForm.js b/renderer/components/Settings/SettingsForm.js
index 9f8c792bd16..f5b7712cf57 100644
--- a/renderer/components/Settings/SettingsForm.js
+++ b/renderer/components/Settings/SettingsForm.js
@@ -1,6 +1,5 @@
 import React from 'react'
 import PropTypes from 'prop-types'
-import get from 'lodash/get'
 import { injectIntl } from 'react-intl'
 import { intlShape } from '@zap/i18n'
 import { Form } from 'components/Form'
@@ -19,11 +18,6 @@ const SettingsForm = ({
 }) => {
   const handleSubmit = async values => {
     try {
-      // If password feature has been disabled, reset the password to null.
-      if (!get(values, 'password.value')) {
-        values.password.value = null
-      }
-
       // Save the updated settings.
       await saveConfigOverrides(values)
 
diff --git a/renderer/components/Settings/SettingsPage.js b/renderer/components/Settings/SettingsPage.js
index 6d52df567b4..5286ee35a0a 100644
--- a/renderer/components/Settings/SettingsPage.js
+++ b/renderer/components/Settings/SettingsPage.js
@@ -11,7 +11,10 @@ import ZapLogo from 'components/Icon/ZapLogo'
 import SettingsForm from 'containers/Settings/SettingsForm'
 import SettingsFieldsWallet from './SettingsFieldsWallet'
 import SettingsFieldsGeneral from './SettingsFieldsGeneral'
-import SettingsFieldsSecurity from './SettingsFieldsSecurity'
+import SettingsFieldsSecurity from 'containers/Settings/SettingsFieldsSecurity'
+import ChangePasswordDialog from 'containers/Settings/ChangePasswordDialog'
+import PasswordPromptDialog from 'containers/Settings/PasswordPromptDialog'
+import PasswordSetDialog from 'containers/Settings/PasswordSetDialog'
 import messages from './messages'
 
 const SettingsMenu = ({ group, setGroup, isLoggedIn, ...rest }) => {
@@ -117,28 +120,33 @@ const SettingsPage = ({ currentConfig, isLoggedIn, ...rest }) => {
   }
 
   return (
-    <Flex width={1} {...rest}>
-      <Sidebar.medium pt={40}>
-        <Panel>
-          <Panel.Header mb={40} px={4}>
-            <ZapLogo height={28} width={28} />
-          </Panel.Header>
-          <Panel.Body sx={{ overflowY: 'overlay' }}>
-            <SettingsMenu group={group} isLoggedIn={isLoggedIn} setGroup={setGroup} />
-          </Panel.Body>
-        </Panel>
-      </Sidebar.medium>
-      <MainContent pb={2} pl={5} pr={6} pt={4}>
-        <Heading.h1 fontSize={60}>
-          <FormattedMessage {...messages.settings_title} />
-        </Heading.h1>
-
-        <SettingsForm>
-          <FieldGroup currentConfig={currentConfig} />
-          <SettingsActions currentConfig={currentConfig} />
-        </SettingsForm>
-      </MainContent>
-    </Flex>
+    <>
+      <Flex width={1} {...rest}>
+        <Sidebar.medium pt={40}>
+          <Panel>
+            <Panel.Header mb={40} px={4}>
+              <ZapLogo height={28} width={28} />
+            </Panel.Header>
+            <Panel.Body sx={{ overflowY: 'overlay' }}>
+              <SettingsMenu group={group} isLoggedIn={isLoggedIn} setGroup={setGroup} />
+            </Panel.Body>
+          </Panel>
+        </Sidebar.medium>
+        <MainContent pb={2} pl={5} pr={6} pt={4}>
+          <Heading.h1 fontSize={60}>
+            <FormattedMessage {...messages.settings_title} />
+          </Heading.h1>
+
+          <SettingsForm>
+            <FieldGroup currentConfig={currentConfig} />
+            <SettingsActions currentConfig={currentConfig} />
+          </SettingsForm>
+        </MainContent>
+      </Flex>
+      <ChangePasswordDialog />
+      <PasswordPromptDialog />
+      <PasswordSetDialog />
+    </>
   )
 }
 
diff --git a/renderer/containers/Settings/ChangePasswordDialog.js b/renderer/containers/Settings/ChangePasswordDialog.js
new file mode 100644
index 00000000000..5a0ec7ef179
--- /dev/null
+++ b/renderer/containers/Settings/ChangePasswordDialog.js
@@ -0,0 +1,27 @@
+import { connect } from 'react-redux'
+import ChangePasswordDialog from 'components/Settings/Security/ChangePasswordDialog'
+import {
+  changePassword as onChange,
+  accountSelectors,
+  clearLoginError,
+  CHANGE_PASSWORD_DIALOG_ID,
+} from 'reducers/account'
+import { modalSelectors, closeDialog } from 'reducers/modal'
+
+const onCancel = () => closeDialog(CHANGE_PASSWORD_DIALOG_ID)
+
+const mapStateToProps = state => ({
+  isOpen: modalSelectors.isDialogOpen(state, CHANGE_PASSWORD_DIALOG_ID),
+  loginError: accountSelectors.loginError(state),
+})
+
+const mapDispatchToProps = {
+  onChange,
+  onCancel,
+  clearLoginError,
+}
+
+export default connect(
+  mapStateToProps,
+  mapDispatchToProps
+)(ChangePasswordDialog)
diff --git a/renderer/containers/Settings/PasswordPromptDialog.js b/renderer/containers/Settings/PasswordPromptDialog.js
new file mode 100644
index 00000000000..d34e04ad2ed
--- /dev/null
+++ b/renderer/containers/Settings/PasswordPromptDialog.js
@@ -0,0 +1,27 @@
+import { connect } from 'react-redux'
+import PasswordPromptDialog from 'components/Settings/Security/PasswordPromptDialog'
+import {
+  accountSelectors,
+  clearLoginError,
+  disablePassword as onOk,
+  PASSWORD_PROMPT_DIALOG_ID,
+} from 'reducers/account'
+import { modalSelectors, closeDialog } from 'reducers/modal'
+
+const onCancel = () => closeDialog(PASSWORD_PROMPT_DIALOG_ID)
+
+const mapStateToProps = state => ({
+  isOpen: modalSelectors.isDialogOpen(state, PASSWORD_PROMPT_DIALOG_ID),
+  loginError: accountSelectors.loginError(state),
+})
+
+const mapDispatchToProps = {
+  onOk,
+  onCancel,
+  clearLoginError,
+}
+
+export default connect(
+  mapStateToProps,
+  mapDispatchToProps
+)(PasswordPromptDialog)
diff --git a/renderer/containers/Settings/PasswordSetDialog.js b/renderer/containers/Settings/PasswordSetDialog.js
new file mode 100644
index 00000000000..e1bb8953fc4
--- /dev/null
+++ b/renderer/containers/Settings/PasswordSetDialog.js
@@ -0,0 +1,21 @@
+import { connect } from 'react-redux'
+import PasswordPromptDialog from 'components/Settings/Security/PasswordPromptDialog'
+import { enablePassword as onOk, PASSWORD_SET_DIALOG_ID } from 'reducers/account'
+import { modalSelectors, closeDialog } from 'reducers/modal'
+
+const onCancel = () => closeDialog(PASSWORD_SET_DIALOG_ID)
+
+const mapStateToProps = state => ({
+  isOpen: modalSelectors.isDialogOpen(state, PASSWORD_SET_DIALOG_ID),
+  isPromptMode: false,
+})
+
+const mapDispatchToProps = {
+  onOk,
+  onCancel,
+}
+
+export default connect(
+  mapStateToProps,
+  mapDispatchToProps
+)(PasswordPromptDialog)
diff --git a/renderer/containers/Settings/SettingsFieldsSecurity.js b/renderer/containers/Settings/SettingsFieldsSecurity.js
new file mode 100644
index 00000000000..9ed65404e7a
--- /dev/null
+++ b/renderer/containers/Settings/SettingsFieldsSecurity.js
@@ -0,0 +1,23 @@
+import { connect } from 'react-redux'
+import SettingsFieldsSecurity from 'components/Settings/SettingsFieldsSecurity'
+import { openDialog } from 'reducers/modal'
+import {
+  CHANGE_PASSWORD_DIALOG_ID,
+  PASSWORD_PROMPT_DIALOG_ID,
+  PASSWORD_SET_DIALOG_ID,
+} from 'reducers/account'
+
+const changePassword = () => openDialog(CHANGE_PASSWORD_DIALOG_ID)
+const disablePassword = () => openDialog(PASSWORD_PROMPT_DIALOG_ID)
+const enablePassword = () => openDialog(PASSWORD_SET_DIALOG_ID)
+
+const mapDispatchToProps = {
+  changePassword,
+  enablePassword,
+  disablePassword,
+}
+
+export default connect(
+  null,
+  mapDispatchToProps
+)(SettingsFieldsSecurity)
diff --git a/renderer/reducers/account.js b/renderer/reducers/account.js
index f45ce9ebfe7..c8759aa7088 100644
--- a/renderer/reducers/account.js
+++ b/renderer/reducers/account.js
@@ -1,6 +1,10 @@
+import { send } from 'redux-electron-ipc'
 import { getIntl } from '@zap/i18n'
+import { sha256digest } from '@zap/utils/crypto'
 import createReducer from './utils/createReducer'
-import { settingsSelectors } from './settings'
+import { settingsSelectors, saveConfigOverrides } from './settings'
+import { closeDialog } from './modal'
+import { showNotification } from './notification'
 import messages from './messages'
 
 // ------------------------------------
@@ -29,6 +33,10 @@ export const LOGIN_SUCCESS = 'LOGIN_SUCCESS'
 export const LOGIN_FAILURE = 'LOGIN_FAILURE'
 export const LOGIN_CLEAR_ERROR = 'LOGIN_CLEAR_ERROR'
 
+export const CHANGE_PASSWORD_DIALOG_ID = 'CHANGE_PASSWORD_DIALOG'
+export const PASSWORD_PROMPT_DIALOG_ID = 'PASSWORD_PROMPT_DIALOG'
+export const PASSWORD_SET_DIALOG_ID = 'PASSWORD_SET_DIALOG_ID'
+
 // ------------------------------------
 // Actions
 // ------------------------------------
@@ -53,21 +61,91 @@ export const initAccount = () => async (dispatch, getState) => {
   }
 }
 
+/**
+ * setPassword - Updates wallet password.
+ *
+ * @param {string} password new password
+ * @returns {Function} Thunk
+ */
+const setPassword = password => async dispatch => {
+  dispatch(send('setPassword', { password: await sha256digest(password) }))
+}
+
+export const changePassword = ({ newPassword, oldPassword }) => async dispatch => {
+  try {
+    const intl = getIntl()
+    await dispatch(requirePassword(oldPassword))
+    await dispatch(setPassword(newPassword))
+    dispatch(closeDialog(CHANGE_PASSWORD_DIALOG_ID))
+    dispatch(showNotification(intl.formatMessage(messages.account_password_updated)))
+  } catch (error) {
+    dispatch({ type: LOGIN_FAILURE, error: error.message })
+  }
+}
+
+export const enablePassword = ({ password }) => async dispatch => {
+  try {
+    const intl = getIntl()
+    dispatch(setPassword(password))
+    dispatch(
+      saveConfigOverrides({
+        password: {
+          active: true,
+        },
+      })
+    )
+    dispatch(closeDialog(PASSWORD_SET_DIALOG_ID))
+    dispatch(showNotification(intl.formatMessage(messages.account_password_enabled)))
+  } catch (error) {
+    dispatch({ type: LOGIN_FAILURE, error: error.message })
+  }
+}
+
+export const disablePassword = ({ password }) => async dispatch => {
+  try {
+    const intl = getIntl()
+    await dispatch(requirePassword(password))
+    dispatch(send('deletePassword'))
+    dispatch(
+      saveConfigOverrides({
+        password: {
+          active: false,
+        },
+      })
+    )
+    dispatch(closeDialog(PASSWORD_PROMPT_DIALOG_ID))
+    dispatch(showNotification(intl.formatMessage(messages.account_password_disabled)))
+  } catch (error) {
+    dispatch({ type: LOGIN_FAILURE, error: error.message })
+  }
+}
+
+const requirePassword = password => dispatch => {
+  return new Promise((resolve, reject) => {
+    dispatch(send('getPassword'))
+    // compare hash received from the main thread to a hash of a password provided
+    window.ipcRenderer.once('getPassword', async (event, { password: hash }) => {
+      const passwordHash = await sha256digest(password)
+      if (hash === passwordHash) {
+        resolve()
+      } else {
+        reject(new Error(getIntl().formatMessage(messages.account_invalid_password)))
+      }
+    })
+  })
+}
+
 /**
  * login - Perform account login.
  *
  * @param {string} password Password
  * @returns {Function} Thunk
  */
-export const login = password => (dispatch, getState) => {
-  dispatch({ type: LOGIN, password })
+export const login = password => async dispatch => {
   try {
-    const accountPassword = accountSelectors.accountPassword(getState())
-    if (accountPassword === password) {
-      dispatch({ type: LOGIN_SUCCESS })
-    } else {
-      throw new Error(getIntl().formatMessage(messages.account_invalid_password))
-    }
+    dispatch({ type: LOGIN, password })
+    await dispatch(requirePassword(password))
+    dispatch({ type: LOGIN_SUCCESS })
   } catch (error) {
     dispatch({ type: LOGIN_FAILURE, error: error.message })
   }
@@ -133,6 +211,8 @@ const isLoggingInSelector = state => state.account.isLoggingIn
 const isLoggedInSelector = state => state.account.isLoggedIn
 const loginErrorSelector = state => state.account.loginError
 
+const isChangePasswordDialogOpenSelector = state => state.account.isChangePasswordDialogOpen
+
 const isAccountPasswordEnabledSelector = state =>
   settingsSelectors.currentConfig(state).password.active
 const accountPasswordSelector = state => settingsSelectors.currentConfig(state).password.value
@@ -149,6 +229,7 @@ accountSelectors.loginError = loginErrorSelector
 
 accountSelectors.isAccountPasswordEnabled = isAccountPasswordEnabledSelector
 accountSelectors.accountPassword = accountPasswordSelector
+accountSelectors.isChangePasswordDialogOpen = isChangePasswordDialogOpenSelector
 
 export { accountSelectors }