diff --git a/ansible/group_vars/all/controllers b/ansible/group_vars/all/controllers
index 6ba4df4f6..16ae8e549 100644
--- a/ansible/group_vars/all/controllers
+++ b/ansible/group_vars/all/controllers
@@ -24,7 +24,8 @@ controller_default_network_interfaces: >
       inspection_net_name,
       internal_net_name,
       storage_net_name,
-      storage_mgmt_net_name] | unique | list }}
+      storage_mgmt_net_name,
+      cleaning_net_name] | unique | list }}
 
 # List of extra networks to which controller nodes are attached.
 controller_extra_network_interfaces: []
diff --git a/ansible/group_vars/all/ironic b/ansible/group_vars/all/ironic
index 643c85d38..8cc9400fb 100644
--- a/ansible/group_vars/all/ironic
+++ b/ansible/group_vars/all/ironic
@@ -112,7 +112,7 @@ kolla_ironic_default_vendor_interface: no-vendor
 kolla_ironic_default_boot_option: local
 
 # Name of the Neutron network to use for cleaning.
-kolla_ironic_cleaning_network: 'provision-net'
+kolla_ironic_cleaning_network: "{{ kolla_ironic_provisioning_network if cleaning_net_name == provision_wl_net_name else 'cleaning-net' }}"
 
 # Name of the Neutron network to use for provisioning.
 kolla_ironic_provisioning_network: 'provision-net'
diff --git a/ansible/group_vars/all/network b/ansible/group_vars/all/network
index 12511a498..3597cf3d6 100644
--- a/ansible/group_vars/all/network
+++ b/ansible/group_vars/all/network
@@ -47,6 +47,10 @@ storage_mgmt_net_name: 'storage_mgmt_net'
 # workload hosts.
 inspection_net_name: 'inspection_net'
 
+# Name of the network used to perform cleaning on the bare metal workload
+# hosts
+cleaning_net_name: "{{ provision_wl_net_name }}"
+
 ###############################################################################
 # Network interface naming conventions.
 
diff --git a/ansible/kolla-ansible.yml b/ansible/kolla-ansible.yml
index 0ffb4098e..32df69ac7 100644
--- a/ansible/kolla-ansible.yml
+++ b/ansible/kolla-ansible.yml
@@ -126,7 +126,7 @@
               {{ kolla_neutron_bridge_interfaces |
                  union([item | net_interface(network_host) | replace('.' ~ item | net_vlan(network_host) | default('!nomatch!'), '')]) |
                  list }}
-          with_items: "{{ [provision_wl_net_name] + external_net_names }}"
+          with_items: "{{ [provision_wl_net_name, cleaning_net_name] + external_net_names | unique | list }}"
           when: item in hostvars[network_host].network_interfaces
 
         - name: Set facts containing the Neutron bridge and interface names
diff --git a/ansible/network.yml b/ansible/network.yml
index 1b5aeec9b..e027c5764 100644
--- a/ansible/network.yml
+++ b/ansible/network.yml
@@ -88,7 +88,7 @@
       set_fact:
         veth_bridge_mtu_map: >
           {{ veth_bridge_mtu_map | combine({interface: mtu}) }}
-      with_items: "{{ [provision_wl_net_name] + external_net_names }}"
+      with_items: "{{ [provision_wl_net_name, cleaning_net_name] + external_net_names | unique | list }}"
       when: item in network_interfaces
       vars:
         interface: "{{ item | net_interface | replace('.' ~ item | net_vlan | default('!nomatch!'), '') }}"
diff --git a/ansible/provision-net.yml b/ansible/provision-net.yml
index 8bc2f3331..13a26c694 100644
--- a/ansible/provision-net.yml
+++ b/ansible/provision-net.yml
@@ -3,17 +3,46 @@
   hosts: controllers
   tags:
     - provision-net
+    - cleaning-net
   tasks:
     - name: Create controllers group with ironic enabled
       group_by:
         key: "controllers_for_provision_net_{{ kolla_enable_ironic | bool }}"
 
-- name: Ensure provisioning network and subnet are registered in neutron
+- name: Ensure provisioning and cleaning networks and subnets are registered in neutron
   # Only required to run on a single host.
   hosts: controllers_for_provision_net_True[0]
   gather_facts: False
+  vars:
+    provision_net:
+      name: "{{ kolla_ironic_provisioning_network }}"
+      provider_network_type: "{% if provision_wl_net_name | net_vlan %}vlan{% else %}flat{% endif %}"
+      provider_physical_network: "{{ provision_wl_net_name | net_physical_network | default('physnet1', True) }}"
+      provider_segmentation_id: "{{ provision_wl_net_name | net_vlan }}"
+      shared: True
+      subnets:
+        - name: "{{ kolla_ironic_provisioning_network }}"
+          cidr: "{{ provision_wl_net_name | net_cidr }}"
+          gateway_ip: "{{ provision_wl_net_name | net_neutron_gateway or provision_wl_net_name | net_gateway }}"
+          allocation_pool_start: "{{ provision_wl_net_name | net_neutron_allocation_pool_start }}"
+          allocation_pool_end: "{{ provision_wl_net_name | net_neutron_allocation_pool_end }}"
+    cleaning_net:
+      name: "{{ kolla_ironic_cleaning_network }}"
+      provider_network_type: "{% if cleaning_net_name | net_vlan %}vlan{% else %}flat{% endif %}"
+      provider_physical_network: "{{ cleaning_net_name | net_physical_network | default('physnet1', True) }}"
+      provider_segmentation_id: "{{ cleaning_net_name | net_vlan }}"
+      shared: True
+      subnets:
+        - name: "{{ kolla_ironic_cleaning_network }}"
+          cidr: "{{ cleaning_net_name | net_cidr }}"
+          gateway_ip: "{{ cleaning_net_name | net_neutron_gateway or cleaning_net_name | net_gateway }}"
+          allocation_pool_start: "{{ cleaning_net_name | net_neutron_allocation_pool_start }}"
+          allocation_pool_end: "{{ cleaning_net_name | net_neutron_allocation_pool_end }}"
+    network_registrations:
+      - "{{ provision_net }}"
   tags:
     - provision-net
+    - cleaning-net
   pre_tasks:
     - name: Validate OpenStack password authentication parameters
       fail:
@@ -34,15 +63,4 @@
       os_networks_auth_type: "{{ openstack_auth_type }}"
       os_networks_auth: "{{ openstack_auth }}"
       # Network configuration.
-      os_networks:
-        - name: "{{ kolla_ironic_provisioning_network }}"
-          provider_network_type: "{% if provision_wl_net_name | net_vlan %}vlan{% else %}flat{% endif %}"
-          provider_physical_network: "{{ provision_wl_net_name | net_physical_network | default('physnet1', True) }}"
-          provider_segmentation_id: "{{ provision_wl_net_name | net_vlan }}"
-          shared: True
-          subnets:
-            - name: "{{ kolla_ironic_provisioning_network }}"
-              cidr: "{{ provision_wl_net_name | net_cidr }}"
-              gateway_ip: "{{ provision_wl_net_name | net_neutron_gateway or provision_wl_net_name | net_gateway }}"
-              allocation_pool_start: "{{ provision_wl_net_name | net_neutron_allocation_pool_start }}"
-              allocation_pool_end: "{{ provision_wl_net_name | net_neutron_allocation_pool_end }}"
+      os_networks: "{{ network_registrations + ([] if cleaning_net_name == provision_wl_net_name else [cleaning_net]) }}"
diff --git a/doc/source/configuration/network.rst b/doc/source/configuration/network.rst
index 1197ec3f4..000d6c2d0 100644
--- a/doc/source/configuration/network.rst
+++ b/doc/source/configuration/network.rst
@@ -410,6 +410,9 @@ Workload out-of-band network (``oob_wl_net_name``)
 Workload provisioning network (``provision_wl_net_name``)
     Name of the network used by the overcloud hosts to provision the bare metal
     workload hosts.
+Workload cleaning network (``cleaning_net_name``)
+    Name of the network used by the overcloud hosts to clean the baremetal
+    workload hosts.
 Internal network (``internal_net_name``)
     Name of the network used to expose the internal OpenStack API endpoints.
 Public network (``public_net_name``)
@@ -447,6 +450,7 @@ To configure network roles in a system with two networks, ``example1`` and
    storage_net_name: example2
    storage_mgmt_net_name: example2
    inspection_net_name: example2
+   cleaning_net_name: example2
 
 Overcloud Provisioning Network
 ------------------------------
@@ -473,6 +477,35 @@ To configure a network called ``example`` with an inspection allocation pool:
    This pool should not overlap with a kayobe allocation pool on the same
    network.
 
+Workload Cleaning Network
+-------------------------
+
+A separate cleaning network, which is used by the overcloud to clean baremetal
+workload (compute) hosts, may optionally be specified. Otherwise,
+the Workload Provisoning network is used. It is necessary to define an IP
+allocation pool for neutron using the
+``neutron_allocation_pool_start`` and ``neutron_allocation_pool_end``
+attributes of the cleaning network. This controls the IP addresses that are
+assigned to workload hosts during cleaning.
+
+.. note::
+
+   This example assumes that the ``example`` network is mapped to
+   ``cleaning_net_name``.
+
+To configure a network called ``example`` with a neutron provisioning
+allocation pool:
+
+.. code-block:: yaml
+
+   example_neutron_allocation_pool_start: 10.0.1.128
+   example_neutron_allocation_pool_end: 10.0.1.195
+
+.. note::
+
+   This pool should not overlap with a kayobe or inspection allocation pool on
+   the same network.
+
 Workload Provisioning Network
 -----------------------------
 
@@ -588,6 +621,7 @@ By default, controllers are attached to the following networks:
 * workload (compute) out-of-band network
 * workload (compute) provisioning network
 * workload (compute) inspection network
+* workload (compute) cleaning network
 * internal network
 * storage network
 * storage management network
diff --git a/etc/kayobe/networks.yml b/etc/kayobe/networks.yml
index 5f61b2ffc..9e10b851b 100644
--- a/etc/kayobe/networks.yml
+++ b/etc/kayobe/networks.yml
@@ -43,6 +43,10 @@
 # workload hosts.
 #inspection_net_name:
 
+# Name of the network used to perform cleaning on the bare metal workload
+# hosts
+#cleaning_net_name:
+
 ###############################################################################
 # Network definitions.
 
@@ -136,6 +140,17 @@
 # storage_mgmt_net_mtu:
 # storage_mgmt_net_routes:
 
+# Cleaning network IP information.
+# cleaning_net_cidr:
+# cleaning_net_allocation_pool_start:
+# cleaning_net_allocation_pool_end:
+# cleaning_net_neutron_allocation_pool_start:
+# cleaning_net_neutron_allocation_pool_end:
+# cleaning_net_gateway:
+# cleaning_net_vlan:
+# cleaning_net_mtu:
+# cleaning_net_routes:
+
 ###############################################################################
 # Network virtual patch link configuration.