Index: src/wp-admin/includes/class-wp-privacy-data-export-requests-list-table.php
===================================================================
--- src/wp-admin/includes/class-wp-privacy-data-export-requests-list-table.php	(revision 49257)
+++ src/wp-admin/includes/class-wp-privacy-data-export-requests-list-table.php	(working copy)
@@ -50,7 +50,7 @@
 		$request_id      = $item->ID;
 		$nonce           = wp_create_nonce( 'wp-privacy-export-personal-data-' . $request_id );
 
-		$download_data_markup = '<div class="export-personal-data" ' .
+		$download_data_markup = '<span class="export-personal-data" ' .
 			'data-exporters-count="' . esc_attr( $exporters_count ) . '" ' .
 			'data-request-id="' . esc_attr( $request_id ) . '" ' .
 			'data-nonce="' . esc_attr( $nonce ) .
@@ -61,10 +61,39 @@
 			'<span class="export-personal-data-success hidden"><button type="button" class="button-link export-personal-data-handle">' . __( 'Download Personal Data Again' ) . '</button></span>' .
 			'<span class="export-personal-data-failed hidden">' . __( 'Download failed.' ) . ' <button type="button" class="button-link">' . __( 'Retry' ) . '</button></span>';
 
-		$download_data_markup .= '</div>';
+		$download_data_markup .= '</span>';
 
+		if ( 'request-completed' !== $status ) {
+			$complete_request_markup  = '<span>';
+			$complete_request_markup .= sprintf(
+				'<a href="%s" class="complete-request" aria-label="%s">%s</a>',
+				esc_url(
+					wp_nonce_url(
+						add_query_arg(
+							array(
+								'action'     => 'complete',
+								'request_id' => array( $request_id ),
+							),
+							admin_url( 'export-personal-data.php' )
+						),
+						'bulk-privacy_requests'
+					)
+				),
+				esc_attr(
+					sprintf(
+						/* translators: %s: Request email. */
+						__( 'Mark export request for &#8220;%s&#8221; as completed.' ),
+						$item->email
+					)
+				),
+				__( 'Complete Request' )
+			);
+			$complete_request_markup .= '</span>';
+		}
+
 		$row_actions = array(
-			'download-data' => $download_data_markup,
+			'download-data'    => $download_data_markup,
+			'complete-request' => $complete_request_markup,
 		);
 
 		return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( $row_actions ) );
Index: src/wp-admin/includes/class-wp-privacy-data-removal-requests-list-table.php
===================================================================
--- src/wp-admin/includes/class-wp-privacy-data-removal-requests-list-table.php	(revision 49257)
+++ src/wp-admin/includes/class-wp-privacy-data-removal-requests-list-table.php	(working copy)
@@ -47,7 +47,8 @@
 		$row_actions = array();
 
 		// Allow the administrator to "force remove" the personal data even if confirmation has not yet been received.
-		$status = $item->status;
+		$status      = $item->status;
+		$row_actions = array();
 		if ( 'request-confirmed' !== $status ) {
 			/** This filter is documented in wp-admin/includes/ajax-actions.php */
 			$erasers       = apply_filters( 'wp_privacy_personal_data_erasers', array() );
@@ -55,7 +56,7 @@
 			$request_id    = $item->ID;
 			$nonce         = wp_create_nonce( 'wp-privacy-erase-personal-data-' . $request_id );
 
-			$remove_data_markup = '<div class="remove-personal-data force-remove-personal-data" ' .
+			$remove_data_markup = '<span class="remove-personal-data force-remove-personal-data" ' .
 				'data-erasers-count="' . esc_attr( $erasers_count ) . '" ' .
 				'data-request-id="' . esc_attr( $request_id ) . '" ' .
 				'data-nonce="' . esc_attr( $nonce ) .
@@ -66,13 +67,41 @@
 				'<span class="remove-personal-data-success hidden">' . __( 'Erasure completed.' ) . '</span>' .
 				'<span class="remove-personal-data-failed hidden">' . __( 'Force Erasure has failed.' ) . ' <button type="button" class="button-link remove-personal-data-handle">' . __( 'Retry' ) . '</button></span>';
 
-			$remove_data_markup .= '</div>';
+			$remove_data_markup .= '</span>';
 
-			$row_actions = array(
-				'remove-data' => $remove_data_markup,
+			$row_actions['remove-data'] = $remove_data_markup;
+		}
+
+		if ( 'request-completed' !== $status ) {
+			$complete_request_markup  = '<span>';
+			$complete_request_markup .= sprintf(
+				'<a href="%s" class="complete-request" aria-label="%s">%s</a>',
+				esc_url(
+					wp_nonce_url(
+						add_query_arg(
+							array(
+								'action'     => 'complete',
+								'request_id' => array( $request_id ),
+							),
+							admin_url( 'erase-personal-data.php' )
+						),
+						'bulk-privacy_requests'
+					)
+				),
+				esc_attr(
+					sprintf(
+						/* translators: %s: Request email. */
+						__( 'Mark export request for &#8220;%s&#8221; as completed.' ),
+						$item->email
+					)
+				),
+				__( 'Complete Request' )
 			);
+			$complete_request_markup .= '</span>';
 		}
 
+		$row_actions['complete-request'] = $complete_request_markup;
+
 		return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( $row_actions ) );
 	}
 
Index: src/wp-admin/includes/class-wp-privacy-requests-table.php
===================================================================
--- src/wp-admin/includes/class-wp-privacy-requests-table.php	(revision 49257)
+++ src/wp-admin/includes/class-wp-privacy-requests-table.php	(working copy)
@@ -210,8 +210,9 @@
 	 */
 	protected function get_bulk_actions() {
 		return array(
-			'delete' => __( 'Delete Requests' ),
-			'resend' => __( 'Resend Confirmation Requests' ),
+			'resend'   => __( 'Resend Confirmation Requests' ),
+			'complete' => __( 'Mark Requests as Completed' ),
+			'delete'   => __( 'Delete Requests' ),
 		);
 	}
 
@@ -219,6 +220,7 @@
 	 * Process bulk actions.
 	 *
 	 * @since 4.9.6
+	 * @since 5.6.0 Added support for the `complete` action.
 	 */
 	public function process_bulk_action() {
 		$action      = $this->current_action();
@@ -231,10 +233,12 @@
 		}
 
 		switch ( $action ) {
-			case 'delete':
+			case 'resend':
 				foreach ( $request_ids as $request_id ) {
-					if ( wp_delete_post( $request_id, true ) ) {
-						$count ++;
+					$resend = _wp_privacy_resend_request( $request_id );
+
+					if ( $resend && ! is_wp_error( $resend ) ) {
+						$count++;
 					}
 				}
 
@@ -242,15 +246,15 @@
 					'bulk_action',
 					'bulk_action',
 					/* translators: %d: Number of requests. */
-					sprintf( _n( 'Deleted %d request.', 'Deleted %d requests.', $count ), $count ),
+					sprintf( _n( 'Re-sent %d request.', 'Re-sent %d requests.', $count ), $count ),
 					'success'
 				);
 				break;
-			case 'resend':
+			case 'complete':
 				foreach ( $request_ids as $request_id ) {
-					$resend = _wp_privacy_resend_request( $request_id );
+					$result = _wp_privacy_completed_request( $request_id );
 
-					if ( $resend && ! is_wp_error( $resend ) ) {
+					if ( $result && ! is_wp_error( $result ) ) {
 						$count++;
 					}
 				}
@@ -259,10 +263,25 @@
 					'bulk_action',
 					'bulk_action',
 					/* translators: %d: Number of requests. */
-					sprintf( _n( 'Re-sent %d request.', 'Re-sent %d requests.', $count ), $count ),
+					sprintf( _n( '%d request marked as complete.', '%d requests marked as complete.', $count ), $count ),
 					'success'
 				);
 				break;
+			case 'delete':
+				foreach ( $request_ids as $request_id ) {
+					if ( wp_delete_post( $request_id, true ) ) {
+						$count ++;
+					}
+				}
+
+				add_settings_error(
+					'bulk_action',
+					'bulk_action',
+					/* translators: %d: Number of requests. */
+					sprintf( _n( 'Deleted %d request.', 'Deleted %d requests.', $count ), $count ),
+					'success'
+				);
+				break;
 		}
 	}
 
