diff --git a/Documentation/Form.rst b/Documentation/Form.rst
index 40ee60544e3ed9d3907ecbef39d8fb52605062b4..908f51a119efd8528ac7ce92252c6d9584067765 100644
--- a/Documentation/Form.rst
+++ b/Documentation/Form.rst
@@ -2728,17 +2728,35 @@ record (defined by `multiSql`).
 
 The Form is shown as a HTML table.
 
-* `multiSql`: Selects the records where the defined FormElements will work on each.
+* *multiSql* =  `<string>` - Selects the records where the defined FormElements will work on each.
 
   * A uniq column `id` or `_id` (not shown) is mandatory and has to reference an existing record in table `primary table`.
   * Additional columns, defined in `multiSql`, will be shown on the form on the same line, before the FormElements.
   * Per row, the STORE_PARENT is filled with the current record of the primary table.
+  * The optional special column `_processRow` will uncheck/check the processRow checkbox during form load.
+
+Process Row
+^^^^^^^^^^^
+
+Activating `processRow` adds a checkbox to every row of the `Multi Form`, including the header.
+During `save`, only selected rows get processed.
+
+The checkbox in the header selects all/none rows at once.
+
+* `Form.parameter`:
+
+  * *processRow* =  `<string>` - the value displayed in table header next to the checkbox.
+
+* `Form.mulitSql`: If there is a column `_processRow`, value of 0/1 per row will control unchecked/checked during form load.
+
+Implicit Multi Form mode
+^^^^^^^^^^^^^^^^^^^^^^^^
 
 The following definition of *Simple* and *Advanced* is just for explanation, there is no *flag* or *mode* which
 has to be set. Also the *Simple* and *Advanced* variant can be mixed in the same Multi Form.
 
 Simple
-^^^^^^
+""""""
 
 General:
 
@@ -2753,7 +2771,7 @@ FormElement:
 * No further definition (`sqlInsert`, `sqlUpdate`, ...) is required.
 
 Advanced
-^^^^^^^^
+""""""""
 
 To handle foreign records (insert/update/delete), use the :ref:`slave-id` concept.
 
diff --git a/extension/Classes/Core/AbstractBuildForm.php b/extension/Classes/Core/AbstractBuildForm.php
index c936c6096db45a3a88d758febc0e3c7a4f6f1dce..28fe871a9502044176d0337be67c5e3158bee926 100644
--- a/extension/Classes/Core/AbstractBuildForm.php
+++ b/extension/Classes/Core/AbstractBuildForm.php
@@ -198,16 +198,34 @@ abstract class AbstractBuildForm {
         $rcJson = array();
 
         $parentRecords = $this->evaluate->parse($this->formSpec[F_MULTI_SQL], ROW_REGULAR);
+        // Check for 'id' or '_id' as column name
+        $idName = isset($parentRecords[0]['_' . F_MULTI_COL_ID]) ? '_' . F_MULTI_COL_ID : F_MULTI_COL_ID;
+
+        // If form.parameter.processRow is set, checkboxes are added to parentRecords
+        if (isset($this->formSpec[F_PROCESS_ROW])) {
+            // Title from query.
+            $processRowTitle = $this->formSpec[F_PROCESS_ROW];
+
+            // Will be displayed in <th></th>.
+            $processRowKey = '<label class="checkbox process-row-all process-row-label-header"><input type="checkbox"><span>' . $processRowTitle . '</span></label>';
+            foreach ($parentRecords as &$array) {
+                // Will be displayed in <td></td>.
+                $checked = empty($array[F_PROCESS_ROW_COLUMN]) ? '' : 'checked="checked"';
+                $processRowName = HelperFormElement::buildFormElementName([FE_NAME => F_PROCESS_ROW_COLUMN], $array[$idName]);
+                $processRowValue = '<label class="checkbox"><input name="' . $processRowName .
+                    '" type="checkbox" ' . $checked . '></label>';
+                $processRow = [$processRowKey => $processRowValue];
+                // Inserted at index 0 and thus displayed in first column of table.
+                $array = $processRow + $array;
+            }
+        }
 
         // No rows: nothing to do.
         if (empty($parentRecords)) {
             return $this->formSpec[F_MULTI_MSG_NO_RECORD];
         }
 
-        // Check for 'id' or '_id' as column name
-        $idName = isset($parentRecords[0]['_' . F_MULTI_COL_ID]) ? '_' . F_MULTI_COL_ID : F_MULTI_COL_ID;
-
-        // Check that an column 'id' is given
+        // Check that a column 'id' is given
         if (!isset($parentRecords[0][$idName])) {
             throw new \UserFormException(
                 json_encode([ERROR_MESSAGE_TO_USER => 'Missing column "_' . F_MULTI_COL_ID . '"', ERROR_MESSAGE_TO_DEVELOPER => $this->formSpec[F_MULTI_SQL]]),
@@ -254,7 +272,7 @@ abstract class AbstractBuildForm {
 
         $tableHead = Support::wrapTag('<tr>', $this->buildMultiFormTableHead($parentRecords[0]));
 
-        return '<table class="table"><thead>' . $tableHead . '</thead><tbody>' . $htmlElements . '</tbody></table>';
+        return '<table class="table table-multi-form qfq-table-100"><thead>' . $tableHead . '</thead><tbody>' . $htmlElements . '</tbody></table>';
     }
 
     /**
diff --git a/extension/Classes/Core/Constants.php b/extension/Classes/Core/Constants.php
index 5adc69dda57c9ac5edfd054c4665dd08060d38c3..0883c276e2cea60dd0615a1a98d60429b7b9bc96 100644
--- a/extension/Classes/Core/Constants.php
+++ b/extension/Classes/Core/Constants.php
@@ -1160,6 +1160,9 @@ const F_MODE_REQUIRED_OFF_BUT_MARK = 'requiredOffButMark';
 const F_MODE_SKIP_REQUIRED_CHECK = 'skipRequiredCheck'; // deprecated since third revision of #9617
 const F_MODE_GLOBAL = 'formModeGlobal';
 
+const F_PROCESS_ROW = 'processRow';
+const F_PROCESS_ROW_COLUMN = '_processRow';
+
 const F_SAVE_BUTTON_ACTIVE = 'saveButtonActive';
 
 const F_SAVE_BUTTON_TEXT = SYSTEM_SAVE_BUTTON_TEXT;
diff --git a/extension/Classes/Core/Save.php b/extension/Classes/Core/Save.php
index f87d1df10f11f40877a7579a6a85d52731d6ffde..ea55fa131b52555fa74ba7769aaac36bc77bca85 100644
--- a/extension/Classes/Core/Save.php
+++ b/extension/Classes/Core/Save.php
@@ -279,9 +279,18 @@ class Save {
 
         $fillStoreForm = new FillStoreForm();
         $storeVarBase = $this->store->getStore(STORE_VAR);
+        $flagCheckProcessRow = isset($this->formSpec[F_PROCESS_ROW]) && $this->formSpec[F_PROCESS_ROW] != '0';
 
         foreach ($parentRecords as $row) {
 
+            // Checks if row has to be processed.
+            if ($flagCheckProcessRow) {
+                $processRowName = HelperFormElement::buildFormElementName([FE_NAME => F_PROCESS_ROW_COLUMN], $row[$idName]);
+                if ('on' !== $this->store->getVar($processRowName, STORE_CLIENT . STORE_ZERO, SANITIZE_ALLOW_ALNUMX)) {
+                    continue;
+                }
+            }
+
             // Always start with a clean STORE_VAR
             $this->store->setStore($storeVarBase, STORE_VAR, true);
 
@@ -298,7 +307,8 @@ class Save {
             $rc = $this->processSingle($row[$idName], $formAction);
         }
 
-        return $rc;
+        // If no rows are selected, saving is still possible, thus requiring a null coalescing operator.
+        return $rc ?? '';
     }
 
     /**
diff --git a/javascript/src/QfqForm.js b/javascript/src/QfqForm.js
index 94b73d8f5f971a616746fbd0b466ff4aab65e921..5c8ca6f448d4077aeb61294162d38a366983e5b9 100644
--- a/javascript/src/QfqForm.js
+++ b/javascript/src/QfqForm.js
@@ -164,6 +164,13 @@ var QfqNS = QfqNS || {};
         $(".radio").append($("<span>", { class: "checkmark", aria: "hidden"}));
         $(".checkbox").append($("<span>", { class: "checkmark", aria: "hidden"}));
 
+        // Feature process all rows
+        $(".process-row-all input[type=checkbox]").on("click", function() {
+            var checkboxes = document.querySelectorAll('input[name^="_processRow-"]');
+            for (var i = 0; i < checkboxes.length; i++) {
+                checkboxes[i].checked = $(this).is(':checked');
+            }
+        });
     };
 
     n.QfqForm.prototype.on = n.EventEmitter.onMixin;
diff --git a/less/qfq-bs.css.less b/less/qfq-bs.css.less
index bed131f411283ea737a408ce52e9e84d4367bd3b..b770118764ce96dffd402247981eda06fb1a47c8 100644
--- a/less/qfq-bs.css.less
+++ b/less/qfq-bs.css.less
@@ -1466,4 +1466,15 @@ input.qfq-password {
 
 .CodeMirror {
   resize: both;
+}
+
+// lower min-height for checkbox in header
+.process-row-label-header {
+  min-height: 20px !important;
+  font-weight: bold;
+}
+
+//
+.table-multi-form > tbody > tr > td {
+  vertical-align: middle;
 }
\ No newline at end of file