diff --git a/playbooks/roles/zuul-executor/tasks/graceful.yaml b/playbooks/roles/zuul-executor/tasks/graceful.yaml
new file mode 100644
index 0000000000..503253a9e0
--- /dev/null
+++ b/playbooks/roles/zuul-executor/tasks/graceful.yaml
@@ -0,0 +1,18 @@
+- name: Gracefully stop Zuul Executor
+  shell:
+    cmd: docker-compose exec executor zuul-executor graceful
+    chdir: /etc/zuul-executor
+  become: true
+  become_user: root
+- name: Wait for Zuul Executor to stop
+  shell:
+    cmd: docker-compose ps -q | xargs docker wait
+    chdir: /etc/zuul-executor
+  become: true
+  become_user: root
+- name: Remove Zuul Executor containers
+  shell:
+    cmd: docker-compose down
+    chdir: /etc/zuul-executor
+  become: true
+  become_user: root
diff --git a/playbooks/roles/zuul-merger/tasks/graceful.yaml b/playbooks/roles/zuul-merger/tasks/graceful.yaml
new file mode 100644
index 0000000000..37da7ac8d0
--- /dev/null
+++ b/playbooks/roles/zuul-merger/tasks/graceful.yaml
@@ -0,0 +1,18 @@
+- name: Gracefully stop Zuul Merger
+  shell:
+    cmd: docker-compose exec merger zuul-merger stop
+    chdir: /etc/zuul-merger
+  become: true
+  become_user: root
+- name: Wait for Zuul Merger to stop
+  shell:
+    cmd: docker-compose ps -q | xargs docker wait
+    chdir: /etc/zuul-merger
+  become: true
+  become_user: root
+- name: Down Zuul Merger containers
+  shell:
+    cmd: docker-compose down
+    chdir: /etc/zuul-merger
+  become: true
+  become_user: root
diff --git a/playbooks/zuul_rolling_restart.yaml b/playbooks/zuul_rolling_restart.yaml
new file mode 100644
index 0000000000..ffce54f482
--- /dev/null
+++ b/playbooks/zuul_rolling_restart.yaml
@@ -0,0 +1,23 @@
+# Run this with "-f 20"
+
+- hosts: 'zuul-merger:!disabled'
+  tasks:
+    - include_role:
+        name: zuul-merger
+        tasks_from: graceful
+
+- hosts: 'zuul-executor:!disabled'
+  serial: 6
+  tasks:
+    - include_role:
+        name: zuul-executor
+        tasks_from: graceful
+    - include_role:
+        name: zuul-executor
+        tasks_from: start
+
+- hosts: 'zuul-merger:!disabled'
+  tasks:
+    - include_role:
+        name: zuul-merger
+        tasks_from: start