diff --git a/.release b/.release
index eb100b2b0e6722fd4bc3289a31bd3903af80d890..02f219ab46a84e7ed5f50ed35b5e6536a431fc21 100644
--- a/.release
+++ b/.release
@@ -1,2 +1,2 @@
-release=0.6.2
-tag=lmcbaseclasses-0.6.2
+release=0.6.3
+tag=lmcbaseclasses-0.6.3
diff --git a/README.md b/README.md
index a95d8a3fedda66df4e51a57283cfbb2fccf534b8..55520e446b963fa62a4fc956ae363662ac7cfb0b 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,9 @@ The lmc-base-classe repository contains set of eight classes as mentioned in SKA
 
 ## Version History
 
+#### 0.6.3
+- Fix omission of fatal_error transition from base device state machine.
+
 #### 0.6.2
 - Fix issue with incorrect updates to transitions dict from inherited devices.
   Only noticeable if running multiple devices of different types in the same
diff --git a/docs/source/SKABaseDevice.rst b/docs/source/SKABaseDevice.rst
index 9d41032725d5449356f3100f4035213ed5a81c07..4e6bcb44ad1ec4d5feb0cb2a8ff2353eb78d963b 100644
--- a/docs/source/SKABaseDevice.rst
+++ b/docs/source/SKABaseDevice.rst
@@ -6,6 +6,14 @@
 SKA BaseDevice
 ============================================
 
+The SKABaseDevice implements the basic device state machine, as illustrated
+below, but without, at present, a Standby state.
+
+.. image:: images/device_state_diagram.png
+  :width: 400
+  :alt: Diagram of the device state machine showing states and transitions
+
+
 .. toctree::
    :maxdepth: 2
 
diff --git a/docs/source/images/device_state_diagram.png b/docs/source/images/device_state_diagram.png
new file mode 100644
index 0000000000000000000000000000000000000000..839caca46bad985fb1d6b59e5e6728e2d1ca5a35
Binary files /dev/null and b/docs/source/images/device_state_diagram.png differ
diff --git a/src/ska/base/base_device.py b/src/ska/base/base_device.py
index e44dddfd72f12e236c3fd52b2f1a77b031fed9f5..30852c8c0c30dff6bf93101c09c0eb58d1dd70a7 100644
--- a/src/ska/base/base_device.py
+++ b/src/ska/base/base_device.py
@@ -477,7 +477,7 @@ class SKABaseDeviceStateModel(DeviceStateModel):
             lambda self: self._set_dev_state(DevState.ON)
         ),
         ('OFF', 'on_failed'): (
-            "FAULT",
+            "FAULT (ENABLED)",
             lambda self: self._set_dev_state(DevState.FAULT)
         ),
         ('ON', 'off_succeeded'): (
@@ -485,7 +485,11 @@ class SKABaseDeviceStateModel(DeviceStateModel):
             lambda self: self._set_dev_state(DevState.OFF)
         ),
         ('ON', 'off_failed'): (
-            "FAULT",
+            "FAULT (ENABLED)",
+            lambda self: self._set_dev_state(DevState.FAULT)
+        ),
+        ('ON', 'fatal_error'): (
+            "FAULT (ENABLED)",
             lambda self: self._set_dev_state(DevState.FAULT)
         ),
 
diff --git a/src/ska/base/release.py b/src/ska/base/release.py
index c5877ac7d47e1f83bcea9acb75bfcefda3047c4a..1afbbc52106869070e5e007bea9f57606139e4eb 100644
--- a/src/ska/base/release.py
+++ b/src/ska/base/release.py
@@ -7,7 +7,7 @@
 """Release information for lmc-base-classes Python Package"""
 
 name = """lmcbaseclasses"""
-version = "0.6.2"
+version = "0.6.3"
 version_info = version.split(".")
 description = """A set of generic base devices for SKA Telescope."""
 author = "SKA India and SARAO and CSIRO"
diff --git a/tests/conftest.py b/tests/conftest.py
index ebf675836329536662629c16660fdd35f3a4a292..081bfde7aa24b99c8ba7d5d5827d75552ed536fb 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -8,8 +8,6 @@ from queue import Empty, Queue
 from tango import EventType
 from tango.test_context import DeviceTestContext
 
-from ska.base import SKASubarrayStateModel
-
 
 @pytest.fixture(scope="class")
 def tango_context(request):
@@ -67,14 +65,6 @@ def initialize_device(tango_context):
     yield tango_context.device.Init()
 
 
-@pytest.fixture(scope="function")
-def state_model():
-    """
-    Yields an SKASubarrayStateModel.
-    """
-    yield SKASubarrayStateModel()
-
-
 @pytest.fixture(scope="function")
 def tango_change_event_helper(tango_context):
     """
diff --git a/tests/test_base_device.py b/tests/test_base_device.py
index b5c47cfe73c5000d7520bfd6860de8e39e44f002..dfe59795963417f50af18cfea014b32fffdd837d 100644
--- a/tests/test_base_device.py
+++ b/tests/test_base_device.py
@@ -8,6 +8,7 @@
 #########################################################################################
 """Contain the tests for the SKABASE."""
 
+import itertools
 import re
 import pytest
 
@@ -18,6 +19,7 @@ import tango
 
 from unittest import mock
 from tango import DevFailed, DevState
+from ska.base import SKABaseDeviceStateModel
 from ska.base.control_model import (
     AdminMode, ControlMode, HealthState, LoggingLevel, SimulationMode, TestMode
 )
@@ -28,6 +30,8 @@ from ska.base.base_device import (
     LoggingTargetError,
     TangoLoggingServiceHandler,
 )
+from ska.base.faults import StateModelError
+
 # PROTECTED REGION END #    //  SKABaseDevice.test_additional_imports
 # Device test case
 # PROTECTED REGION ID(SKABaseDevice.test_SKABaseDevice_decorators) ENABLED START #
@@ -583,3 +587,145 @@ class TestSKABaseDevice(object):
         # PROTECTED REGION ID(SKABaseDevice.test_testMode) ENABLED START #
         assert tango_context.device.testMode == TestMode.NONE
         # PROTECTED REGION END #    //  SKABaseDevice.test_testMode
+
+
+@pytest.fixture
+def state_model():
+    yield SKABaseDeviceStateModel()
+
+
+class TestSKABaseDeviceStateModel():
+    """
+    Test cases for SKABaseDeviceStateModel.
+    """
+
+    @pytest.mark.parametrize(
+        'state_under_test, action_under_test',
+        itertools.product(
+            ["UNINITIALISED", "INIT_ENABLED", "INIT_DISABLED", "FAULT_ENABLED",
+             "FAULT_DISABLED", "DISABLED", "OFF", "ON"],
+            ["init_started", "init_succeeded", "init_failed", "fatal_error",
+             "reset_succeeded", "reset_failed", "to_notfitted",
+             "to_offline", "to_online", "to_maintenance", "on_succeeded",
+             "on_failed", "off_succeeded", "off_failed"]
+        )
+    )
+    def test_state_machine(
+        self, state_model, state_under_test, action_under_test
+    ):
+        """
+        Test the subarray state machine: for a given initial state and
+        an action, does execution of that action, from that initial
+        state, yield the expected results? If the action was not allowed
+        from that initial state, does the device raise a DevFailed
+        exception? If the action was allowed, does it result in the
+        correct state transition?
+
+        :todo: support starting in different memorised adminModes
+        """
+        states = {
+            "UNINITIALISED":
+                (None, None),
+            "FAULT_ENABLED":
+                ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.FAULT),
+            "FAULT_DISABLED":
+                ([AdminMode.NOT_FITTED, AdminMode.OFFLINE], DevState.FAULT),
+            "INIT_ENABLED":
+                ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.INIT),
+            "INIT_DISABLED":
+                ([AdminMode.NOT_FITTED, AdminMode.OFFLINE], DevState.INIT),
+            "DISABLED":
+                ([AdminMode.NOT_FITTED, AdminMode.OFFLINE], DevState.DISABLE),
+            "OFF":
+                ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.OFF),
+            "ON":
+                ([AdminMode.ONLINE, AdminMode.MAINTENANCE], DevState.ON),
+        }
+
+        def assert_state(state):
+            (admin_modes, state) = states[state]
+            if admin_modes is not None:
+                assert state_model.admin_mode in admin_modes
+            if state is not None:
+                assert state_model.dev_state == state
+
+        transitions = {
+            ('UNINITIALISED', 'init_started'): "INIT_ENABLED",
+            ('INIT_ENABLED', 'to_notfitted'): "INIT_DISABLED",
+            ('INIT_ENABLED', 'to_offline'): "INIT_DISABLED",
+            ('INIT_ENABLED', 'to_online'): "INIT_ENABLED",
+            ('INIT_ENABLED', 'to_maintenance'): "INIT_ENABLED",
+            ('INIT_ENABLED', 'init_succeeded'): 'OFF',
+            ('INIT_ENABLED', 'init_failed'): 'FAULT_ENABLED',
+            ('INIT_ENABLED', 'fatal_error'): "FAULT_ENABLED",
+            ('INIT_DISABLED', 'to_notfitted'): "INIT_DISABLED",
+            ('INIT_DISABLED', 'to_offline'): "INIT_DISABLED",
+            ('INIT_DISABLED', 'to_online'): "INIT_ENABLED",
+            ('INIT_DISABLED', 'to_maintenance'): "INIT_ENABLED",
+            ('INIT_DISABLED', 'init_succeeded'): 'DISABLED',
+            ('INIT_DISABLED', 'init_failed'): 'FAULT_DISABLED',
+            ('INIT_DISABLED', 'fatal_error'): "FAULT_DISABLED",
+            ('FAULT_DISABLED', 'to_notfitted'): "FAULT_DISABLED",
+            ('FAULT_DISABLED', 'to_offline'): "FAULT_DISABLED",
+            ('FAULT_DISABLED', 'to_online'): "FAULT_ENABLED",
+            ('FAULT_DISABLED', 'to_maintenance'): "FAULT_ENABLED",
+            ('FAULT_DISABLED', 'reset_succeeded'): "DISABLED",
+            ('FAULT_DISABLED', 'reset_failed'): "FAULT_DISABLED",
+            ('FAULT_DISABLED', 'fatal_error'): "FAULT_DISABLED",
+            ('FAULT_ENABLED', 'to_notfitted'): "FAULT_DISABLED",
+            ('FAULT_ENABLED', 'to_offline'): "FAULT_DISABLED",
+            ('FAULT_ENABLED', 'to_online'): "FAULT_ENABLED",
+            ('FAULT_ENABLED', 'to_maintenance'): "FAULT_ENABLED",
+            ('FAULT_ENABLED', 'reset_succeeded'): "OFF",
+            ('FAULT_ENABLED', 'reset_failed'): "FAULT_ENABLED",
+            ('FAULT_ENABLED', 'fatal_error'): "FAULT_ENABLED",
+            ('DISABLED', 'to_notfitted'): "DISABLED",
+            ('DISABLED', 'to_offline'): "DISABLED",
+            ('DISABLED', 'to_online'): "OFF",
+            ('DISABLED', 'to_maintenance'): "OFF",
+            ('DISABLED', 'fatal_error'): "FAULT_DISABLED",
+            ('OFF', 'to_notfitted'): "DISABLED",
+            ('OFF', 'to_offline'): "DISABLED",
+            ('OFF', 'to_online'): "OFF",
+            ('OFF', 'to_maintenance'): "OFF",
+            ('OFF', 'on_succeeded'): "ON",
+            ('OFF', 'on_failed'): "FAULT_ENABLED",
+            ('OFF', 'fatal_error'): "FAULT_ENABLED",
+            ('ON', 'off_succeeded'): "OFF",
+            ('ON', 'off_failed'): "FAULT_ENABLED",
+            ('ON', 'fatal_error'): "FAULT_ENABLED",
+        }
+
+        setups = {
+            "UNINITIALISED": [],
+            "INIT_ENABLED": ['init_started'],
+            "INIT_DISABLED": ['init_started', 'to_offline'],
+            "FAULT_ENABLED": ['init_started', 'init_failed'],
+            "FAULT_DISABLED": ['init_started', 'to_offline', 'init_failed'],
+            "OFF": ['init_started', 'init_succeeded'],
+            "DISABLED": ['init_started', 'init_succeeded', 'to_offline'],
+            "ON": ['init_started', 'init_succeeded', 'on_succeeded'],
+        }
+
+        # state = "UNINITIALISED"  # for test debugging only
+        # assert_state(state)  # for test debugging only
+
+        # Put the device into the state under test
+        for action in setups[state_under_test]:
+            state_model.perform_action(action)
+            # state = transitions[state, action]  # for test debugging only
+            # assert_state(state)  # for test debugging only
+
+        # Check that we are in the state under test
+        assert_state(state_under_test)
+
+        # Test that the action under test does what we expect it to
+        if (state_under_test, action_under_test) in transitions:
+            # Action should succeed
+            state_model.perform_action(action_under_test)
+            assert_state(transitions[(state_under_test, action_under_test)])
+        else:
+            # Action should fail and the state should not change
+            with pytest.raises(StateModelError):
+                state_model.perform_action(action_under_test)
+            assert_state(state_under_test)
diff --git a/tests/test_subarray_device.py b/tests/test_subarray_device.py
index 8abc50cdfcdc62e63c7d0b673dc31ea24cf2e804..ae4a8cade5bc4f254d7ef459aa40ab95d93c1e4b 100644
--- a/tests/test_subarray_device.py
+++ b/tests/test_subarray_device.py
@@ -15,7 +15,7 @@ import pytest
 from tango import DevState, DevFailed
 
 # PROTECTED REGION ID(SKASubarray.test_additional_imports) ENABLED START #
-from ska.base import SKASubarray, SKASubarrayResourceManager
+from ska.base import SKASubarray, SKASubarrayResourceManager, SKASubarrayStateModel
 from ska.base.commands import ResultCode
 from ska.base.control_model import (
     AdminMode, ControlMode, HealthState, ObsMode, ObsState, SimulationMode, TestMode
@@ -579,6 +579,11 @@ def resource_manager():
     yield SKASubarrayResourceManager()
 
 
+@pytest.fixture
+def state_model():
+    yield SKASubarrayStateModel()
+
+
 class TestSKASubarrayResourceManager:
     def test_ResourceManager_assign(self, resource_manager):
         # create a resource manager and check that it is empty
diff --git a/tests/test_subarray_state_model.py b/tests/test_subarray_state_model.py
index 8c8d2f16ccc4e0fd7833ec380510968afbc0a44b..804b8cf98f39e2252297856b24ed29f645395248 100644
--- a/tests/test_subarray_state_model.py
+++ b/tests/test_subarray_state_model.py
@@ -13,11 +13,17 @@ import pytest
 
 from tango import DevState
 
+from ska.base import SKASubarrayStateModel
 from ska.base.control_model import AdminMode, ObsState
 from ska.base.faults import StateModelError
 
 
-class TestSKASubarrayStateModel():
+@pytest.fixture
+def state_model():
+    yield SKASubarrayStateModel()
+
+
+class TestSKASubarrayStateModel:
     """
     Test cases for SKASubarrayStateModel.
     """
@@ -43,8 +49,9 @@ class TestSKASubarrayStateModel():
              "restart_failed"]
         )
     )
-    def test_state_machine(self, state_model,
-                           state_under_test, action_under_test):
+    def test_state_machine(
+        self, state_model, state_under_test, action_under_test
+    ):
         """
         Test the subarray state machine: for a given initial state and
         an action, does execution of that action, from that initial