diff --git a/bescheid-manager/pom.xml b/bescheid-manager/pom.xml
index 1a68e867137a6b69567130194e403315d74c70dd..08aa46a6bad2f372f7a30193c7de3d387a735789 100644
--- a/bescheid-manager/pom.xml
+++ b/bescheid-manager/pom.xml
@@ -12,12 +12,12 @@
 	<groupId>de.ozgcloud.bescheid</groupId>
 	<artifactId>bescheid-manager</artifactId>
 	<name>OZG-Cloud Bescheid Manager</name>
-	<version>1.21.0-SNAPSHOT</version>
+	<version>1.22.0-SNAPSHOT</version>
 
 	<properties>
-		<vorgang-manager.version>2.18.0-SNAPSHOT</vorgang-manager.version>
+		<vorgang-manager.version>2.19.0-SNAPSHOT</vorgang-manager.version>
 		<nachrichten-manager.version>2.14.0</nachrichten-manager.version>
-		<document-manager.version>1.1.0-SNAPSHOT</document-manager.version>
+		<document-manager.version>1.1.0</document-manager.version>
 		<api-lib.version>0.13.0</api-lib.version>
 		<spring-cloud-config-client.version>4.1.3</spring-cloud-config-client.version>
 	</properties>
diff --git a/pom.xml b/pom.xml
index 6b7687d7ad095a08ede0e47302cb681c8758f4d8..494b935a4f31039cfce14ab9cbacf431bcb5b818 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,7 +29,7 @@
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>de.ozgcloud.vorgang</groupId>
 	<artifactId>vorgang-manager</artifactId>
-	<version>2.18.0-SNAPSHOT</version>
+	<version>2.19.0-SNAPSHOT</version>
 
 	<name>OZG-Cloud Vorgang Manager</name>
 	<packaging>pom</packaging>
diff --git a/vorgang-manager-base/pom.xml b/vorgang-manager-base/pom.xml
index c83597fa5a58ebe7a7f6505a895f3a5a4ae57ef2..c7172d29448e987cfdce84cca7f287ac610cdd54 100644
--- a/vorgang-manager-base/pom.xml
+++ b/vorgang-manager-base/pom.xml
@@ -12,7 +12,7 @@
 
 	<groupId>de.ozgcloud.vorgang</groupId>
 	<artifactId>vorgang-manager-base</artifactId>
-	<version>2.18.0-SNAPSHOT</version>
+	<version>2.19.0-SNAPSHOT</version>
 
 	<name>OZG-Cloud Vorgang Manager Base</name>
 
@@ -25,7 +25,7 @@
 			<groupId>org.springframework.security</groupId>
 			<artifactId>spring-security-core</artifactId>
 		</dependency>
-		
+
 		<dependency>
 			<groupId>net.devh</groupId>
 			<artifactId>grpc-server-spring-boot-starter</artifactId>
@@ -34,7 +34,7 @@
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-validation</artifactId>
 		</dependency>
-		
+
 		<!-- TEST -->
 		<dependency>
 			<groupId>org.springframework.security</groupId>
@@ -42,7 +42,7 @@
 			<scope>test</scope>
 		</dependency>
 	</dependencies>
-	
+
 	<build>
 		<plugins>
 			<plugin>
diff --git a/vorgang-manager-command/pom.xml b/vorgang-manager-command/pom.xml
index 43d5db3f766ff8c111b9014da615c53f287fbc39..f93d67bd17606e486b5141534a01bdeba40f5423 100644
--- a/vorgang-manager-command/pom.xml
+++ b/vorgang-manager-command/pom.xml
@@ -7,16 +7,16 @@
 		<version>4.6.0-OZG-7143-download-timeout-SNAPSHOT</version>
 		<relativePath/>
 	</parent>
-	
+
 	<groupId>de.ozgcloud.command</groupId>
 	<artifactId>command-manager</artifactId>
-	<version>2.18.0-SNAPSHOT</version>
+	<version>2.19.0-SNAPSHOT</version>
 	<name>OZG-Cloud Command Manager</name>
 
 	<properties>
 		<maven-jar-plugin.version>3.3.0</maven-jar-plugin.version>
 	</properties>
-	
+
 	<dependencies>
 		<dependency>
 			<groupId>org.springframework</groupId>
@@ -34,7 +34,7 @@
 			<optional>true</optional>
 		</dependency>
 	</dependencies>
-	
+
 	<build>
 		<plugins>
 			<plugin>
diff --git a/vorgang-manager-command/src/main/java/de/ozgcloud/command/VorgangUnlockedEvent.java b/vorgang-manager-command/src/main/java/de/ozgcloud/command/VorgangUnlockedEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..167a7e49b7590fb40f6b7764c0a7feaf1a5d4170
--- /dev/null
+++ b/vorgang-manager-command/src/main/java/de/ozgcloud/command/VorgangUnlockedEvent.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.command;
+
+public class VorgangUnlockedEvent extends CommandExecutedEvent {
+
+	public VorgangUnlockedEvent(Command command) {
+		super(command);
+	}
+}
diff --git a/vorgang-manager-interface/pom.xml b/vorgang-manager-interface/pom.xml
index 27bed8971a78be17aed5f0edba00c03e65b38c66..33a50b101f9f2bd1b7786459f609aba4d804a7f1 100644
--- a/vorgang-manager-interface/pom.xml
+++ b/vorgang-manager-interface/pom.xml
@@ -36,7 +36,7 @@
 
 	<groupId>de.ozgcloud.vorgang</groupId>
 	<artifactId>vorgang-manager-interface</artifactId>
-	<version>2.18.0-SNAPSHOT</version>
+	<version>2.19.0-SNAPSHOT</version>
 
 	<name>OZG-Cloud Vorgang Manager gRPC Interface</name>
 	<description>Interface (gRPC) for Vorgang Manager Server</description>
diff --git a/vorgang-manager-server/pom.xml b/vorgang-manager-server/pom.xml
index 6b32baf91bac7d3f94db0d79f1ad5c7ebec244eb..c2e8544c94f3a2d3665c86e4861e465c9577b3d4 100644
--- a/vorgang-manager-server/pom.xml
+++ b/vorgang-manager-server/pom.xml
@@ -32,13 +32,13 @@
 	<parent>
 		<groupId>de.ozgcloud.common</groupId>
 		<artifactId>ozgcloud-common-parent</artifactId>
-		<version>4.6.0-OZG-7143-download-timeout-SNAPSHOT</version>
+		<version>4.7.0-OZG-7143-download-timeout-SNAPSHOT</version>
 		<relativePath />
 	</parent>
 
 	<groupId>de.ozgcloud.vorgang</groupId>
 	<artifactId>vorgang-manager-server</artifactId>
-	<version>2.18.0-SNAPSHOT</version>
+	<version>2.19.0-SNAPSHOT</version>
 
 	<name>OZG-Cloud Vorgang Manager Server</name>
 	<description>Server Implementierung des VorgangManagers</description>
@@ -53,12 +53,12 @@
 		<zufi-manager-interface.version>1.4.0</zufi-manager-interface.version>
 
 		<user-manager-interface.version>2.9.0</user-manager-interface.version>
-		<bescheid-manager.version>1.21.0-SNAPSHOT</bescheid-manager.version>
+		<bescheid-manager.version>1.22.0-SNAPSHOT</bescheid-manager.version>
 		<processor-manager.version>0.5.0</processor-manager.version>
 		<nachrichten-manager.version>2.14.1</nachrichten-manager.version>
-		<ozgcloud-starter.version>0.14.0-SNAPSHOT</ozgcloud-starter.version>
+		<ozgcloud-starter.version>0.14.0</ozgcloud-starter.version>
 		<notification-manager.version>2.12.0</notification-manager.version>
-		<collaboration-manager.version>0.5.0-SNAPSHOT</collaboration-manager.version>
+		<collaboration-manager.version>0.5.0</collaboration-manager.version>
 		<archive-manager.version>0.1.0-OZG-7143-download-timeout-SNAPSHOT</archive-manager.version>
 		<document-manager.version>1.1.0-SNAPSHOT</document-manager.version>
 
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java
index 7ff69bdda006fb2d969558ea1f60dc7cc23f99e3..735062519c9fab1aded45bb777bdf6492715178e 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java
@@ -72,14 +72,14 @@ public class CommandService {
 	private CurrentUserService userService;
 
 	public Command createCommand(CreateCommandRequest request) {
-		validateVorgang(request.getVorgangId());
+		validateVorgang(request.getVorgangId(), request.getOrder());
 		var persisted = saveCommand(buildCommand(request));
 		publisher.publishEvent(new CommandCreatedEvent(persisted));
 		return persisted;
 	}
 
-	void validateVorgang(String vorgangId) {
-		if (vorgangService.isVorgangLocked(vorgangId)) {
+	void validateVorgang(String vorgangId, String order) {
+		if (!Order.UNLOCK_VORGANG.isMeant(order) && vorgangService.isVorgangLocked(vorgangId)) {
 			throw new TechnicalException("Cannot create command. Vorgang %s is locked.".formatted(vorgangId));
 		}
 	}
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java
index f51468b4f6c1b2b2021edea87a9e3fb718e764b4..8129105065f4ac879de49f0c4eb1b53323e6b0d8 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java
@@ -41,6 +41,7 @@ public enum Order {
 	VORGANG_ZUM_LOESCHEN_MARKIEREN,
 	VORGANG_LOESCHEN,
 	LOCK_VORGANG,
+	UNLOCK_VORGANG,
 
 	ASSIGN_USER,
 
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java
index fe62492f032f6f357a8df8db7fbecee6ce1031c2..326cea62655275c0caa6bd9ddb315a1c5cddef54 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java
@@ -26,7 +26,6 @@ package de.ozgcloud.vorgang.vorgang;
 import java.util.Collections;
 import java.util.function.Predicate;
 
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.context.event.EventListener;
 import org.springframework.stereotype.Component;
@@ -38,41 +37,43 @@ import de.ozgcloud.command.CommandFailedEvent;
 import de.ozgcloud.command.CommandRevokeFailedEvent;
 import de.ozgcloud.command.CommandRevokedEvent;
 import de.ozgcloud.command.RevokeCommandEvent;
+import de.ozgcloud.command.VorgangUnlockedEvent;
 import de.ozgcloud.vorgang.command.CommandService;
 import de.ozgcloud.vorgang.command.Order;
 import de.ozgcloud.vorgang.files.FileService;
 import de.ozgcloud.vorgang.status.StatusService;
 import de.ozgcloud.vorgang.vorgang.redirect.VorgangForwardFailedEvent;
 import de.ozgcloud.vorgang.vorgang.redirect.VorgangRedirectedEvent;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.log4j.Log4j2;
 
 @Component
+@RequiredArgsConstructor
 @Log4j2
 public class VorgangEventListener {
 
 	private static final String IS_ASSIGN_COMMAND_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.VorgangEventListener).IS_ASSIGN_COMMAND.test(event.getSource())}";
-	private static final String IS_LOESCHEN_COMMAND_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.VorgangEventListener).IS_LOESCHEN_COMMAND.test(event.getSource())}";
-	private static final String IS_SET_AKTENZEICHEN_COMMAND_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.VorgangEventListener).IS_SET_AKTENZEICHEN_COMMAND.test(event.getSource())}";
 	public static final Predicate<Command> IS_ASSIGN_COMMAND = command -> Order.ASSIGN_USER.isMeant(command.getOrder());
+
+	private static final String IS_LOESCHEN_COMMAND_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.VorgangEventListener).IS_LOESCHEN_COMMAND.test(event.getSource())}";
 	public static final Predicate<Command> IS_LOESCHEN_COMMAND = command -> Order.VORGANG_LOESCHEN.isMeant(command.getOrder());
+
+	private static final String IS_SET_AKTENZEICHEN_COMMAND_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.VorgangEventListener).IS_SET_AKTENZEICHEN_COMMAND.test(event.getSource())}";
 	public static final Predicate<Command> IS_SET_AKTENZEICHEN_COMMAND = command -> Order.SET_AKTENZEICHEN.isMeant(command.getOrder());
 
 	private static final String IS_LOCK_VORGANG_COMMAND = "{T(de.ozgcloud.vorgang.vorgang.VorgangEventListener).IS_LOCK_VORGANG_ORDER.test(event.getSource())}";
 	public static final Predicate<Command> IS_LOCK_VORGANG_ORDER = command -> Order.LOCK_VORGANG.isMeant(command.getOrder());
 
-	@Autowired
-	private StatusService statusService;
-	@Autowired
-	private VorgangService vorgangService;
-	@Autowired
-	private VorgangHeaderService vorgangHeaderService;
-	@Autowired
-	private FileService fileService;
-	@Autowired
-	private CommandService commandService;
+	private static final String IS_UNLOCK_VORGANG_COMMAND_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.VorgangEventListener).IS_UNLOCK_VORGANG_COMMAND.test(event.getSource())}";
+	public static final Predicate<Command> IS_UNLOCK_VORGANG_COMMAND = command -> Order.UNLOCK_VORGANG.isMeant(command.getOrder());
 
-	@Autowired
-	private ApplicationEventPublisher publisher;
+	private final StatusService statusService;
+	private final VorgangService vorgangService;
+	private final VorgangHeaderService vorgangHeaderService;
+	private final FileService fileService;
+	private final CommandService commandService;
+
+	private final ApplicationEventPublisher publisher;
 
 	@EventListener
 	public void updateStatus(VorgangRedirectedEvent event) {
@@ -153,4 +154,16 @@ public class VorgangEventListener {
 	private String getAktenzeichen(String vorgangId) {
 		return vorgangHeaderService.getById(vorgangId).getAktenzeichen();
 	}
+
+	@EventListener(condition = IS_UNLOCK_VORGANG_COMMAND_CONDITION)
+	public void onUnlockVorgang(CommandCreatedEvent event) {
+		var command = event.getSource();
+		try {
+			vorgangService.unlockVorgang(command);
+			publisher.publishEvent(new VorgangUnlockedEvent(command));
+		} catch (RuntimeException e) {
+			LOG.error("Error unlocking vorgang.", e);
+			publisher.publishEvent(new CommandFailedEvent(command.getId(), e.getMessage()));
+		}
+	}
 }
\ No newline at end of file
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangRepository.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangRepository.java
index 26d04339e3b70b7d4223f9767b369769565e4d2b..73b8056a21f14627df0a698190236e834641e59c 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangRepository.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangRepository.java
@@ -73,10 +73,25 @@ class VorgangRepository {
 	}
 
 	public void patch(String vorgangId, long version, Map<String, Object> patch) {
-		var update = new Update().inc(Vorgang.MONGODB_FIELDNAME_VERSION, 1);
+		updateFirst(vorgangId, whereIdAndVersion(vorgangId, version), createPatchUpdate(patch));
+	}
+
+	private Update createPatchUpdate(Map<String, Object> patch) {
+		var update = createVersionIncUpdate();
 		patch.forEach(update::set);
+		return update;
+	}
+
+	public void removeLock(String vorgangId, long version) {
+		updateFirst(vorgangId, whereIdAndVersion(vorgangId, version), createUnlockUpdate());
+	}
+
+	private Update createUnlockUpdate() {
+		return createVersionIncUpdate().unset(VorgangService.KEY_HEADER_LOCK);
+	}
 
-		updateFirst(vorgangId, whereIdAndVersion(vorgangId, version), update);
+	private Update createVersionIncUpdate() {
+		return new Update().inc(Vorgang.MONGODB_FIELDNAME_VERSION, 1);
 	}
 
 	public void setAktenzeichen(String vorgangId, long version, String akteneinsicht) {
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java
index bb11f2d9dd746310ba8ca7a2aa792347ae74498d..d74495d587f0f340e7cc5ba4bd1362017ff8e4b5 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java
@@ -38,7 +38,6 @@ import jakarta.validation.Valid;
 import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.security.access.AccessDeniedException;
 import org.springframework.stereotype.Service;
@@ -55,33 +54,28 @@ import de.ozgcloud.vorgang.clientattribute.ClientAttributesMap;
 import de.ozgcloud.vorgang.common.errorhandling.NotFoundException;
 import de.ozgcloud.vorgang.servicekonto.ServiceKonto;
 import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
 
 @Validated
 @Service
+@RequiredArgsConstructor
 public class VorgangService {
 
 	private static final String BODY_ASSIGNED_TO_FIELD = "assignedTo";
 	public static final String BODY_OBJECT_AKTENZEICHEN = "aktenzeichen";
 	static final String KEY_HEADER_LOCK = "%s.%s".formatted(Vorgang.MONGODB_FIELDNAME_HEADER, VorgangHead.FIELD_LOCK);
 
-	@Autowired
-	private VorgangAuthorizationService vorgangAuthenticationService;
-	@Autowired
-	private VorgangRepository repository;
+	private final VorgangAuthorizationService vorgangAuthenticationService;
+	private final VorgangRepository repository;
 
-	@Autowired
-	private ApplicationEventPublisher publisher;
-	@Autowired
-	private AktenzeichenProvider aktenzeichenProvider;
+	private final ApplicationEventPublisher publisher;
+	private final AktenzeichenProvider aktenzeichenProvider;
 
-	@Autowired
-	private ClientAttributeReadPermitted readIsPermitted;
+	private final ClientAttributeReadPermitted readIsPermitted;
 
-	@Autowired
-	private LabelProcessor kopControlDataMapper;
+	private final LabelProcessor kopControlDataMapper;
 
-	@Autowired
-	private VorgangStubMapper stubMapper;
+	private final VorgangStubMapper stubMapper;
 
 	public Vorgang startCreation(@Valid Eingang eingang) {
 		var mappedEingang = kopControlDataMapper.moveLabelsToControlData(eingang);
@@ -261,8 +255,24 @@ public class VorgangService {
 	}
 
 	public void unlockVorgang(Command command) {
-		// TODO wird implementiert in OZG-6992
-		// publisher.publishEvent(new CommandRevokedEvent(command));
-		throw new UnsupportedOperationException("Not yet implemented");
+		validateUnlockingClient(command);
+		repository.removeLock(command.getVorgangId(), command.getRelationVersion());
 	}
+
+	void validateUnlockingClient(Command command) {
+		var vorgang = repository.findById(command.getVorgangId()).orElseThrow(() -> new NotFoundException(Vorgang.class, command.getVorgangId()));
+		validateClientName(command.getCreatedByClientName(), Optional.ofNullable(vorgang.getHeader().getLock()));
+	}
+
+	void validateClientName(String commandClientName, Optional<Lock> lock) {
+		if (hasNoPermissionToUnlock(commandClientName, lock)) {
+			throw new AccessDeniedException(
+					"Vorgang was locked by %s, but client name is %s!".formatted(lock.get().getClientName(), commandClientName));
+		}
+	}
+
+	boolean hasNoPermissionToUnlock(String clientName, Optional<Lock> lock) {
+		return lock.map(Lock::getClientName).filter(lockingClient -> !lockingClient.equals(clientName)).isPresent();
+	}
+
 }
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/TestConfiguration.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/TestConfiguration.java
index 5cc668752eae4480fa6c9c8d4767483ab56db5a6..126443e9add8f118d47eb65f7bdc77e64bbc1cfe 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/TestConfiguration.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/TestConfiguration.java
@@ -25,19 +25,13 @@ package de.ozgcloud.vorgang;
 
 import static org.mockito.Mockito.*;
 
-import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.mail.javamail.JavaMailSender;
 
-import de.ozgcloud.archive.common.callcontext.CallContextProvider;
-
 @Configuration
 public class TestConfiguration {
 
-	@MockBean
-	private CallContextProvider callContextProvider;
-
 	@Bean
 	JavaMailSender mockMailSender() {
 		return mock(JavaMailSender.class);
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java
index a129a4c389de52dbf8d0ef358efdec8ea5e6771c..364dfd5ed06c1ed1f95285ac4ac58115721039da 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java
@@ -90,7 +90,7 @@ class CommandServiceTest {
 		void shouldCallValidateVorgang() {
 			service.createCommand(request);
 
-			verify(service).validateVorgang(VorgangTestFactory.ID);
+			verify(service).validateVorgang(VorgangTestFactory.ID, CreateCommandRequestTestFactory.ORDER.name());
 		}
 
 		@Test
@@ -182,16 +182,29 @@ class CommandServiceTest {
 
 		@Test
 		void shouldCallIsVorgangLocked() {
-			service.validateVorgang(VorgangTestFactory.ID);
+			service.validateVorgang(VorgangTestFactory.ID, Order.ASSIGN_USER.name());
 
 			verify(vorgangService).isVorgangLocked(VorgangTestFactory.ID);
 		}
 
 		@Test
 		void shouldThrowExceptionIfVorgangLocked() {
+			var order = Order.ASSIGN_USER.name();
 			when(vorgangService.isVorgangLocked(anyString())).thenReturn(true);
 
-			Assertions.assertThrows(TechnicalException.class, () -> service.validateVorgang(VorgangTestFactory.ID));
+			Assertions.assertThrows(TechnicalException.class, () -> service.validateVorgang(VorgangTestFactory.ID, order));
+		}
+
+		@Test
+		void shouldNotCallIsVorgangLockedForUnlockVorgangOrder() {
+			service.validateVorgang(VorgangTestFactory.ID, Order.UNLOCK_VORGANG.name());
+
+			verify(vorgangService, never()).isVorgangLocked(any());
+		}
+
+		@Test
+		void shouldNotThrowExceptionIfOrderIsUnlockVorgang() {
+			Assertions.assertDoesNotThrow(() -> service.validateVorgang(VorgangTestFactory.ID, Order.UNLOCK_VORGANG.name()));
 		}
 
 	}
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockTestFactory.java
index 7b4905e5280cf65dc77a65dae4888feb035e7f01..cdbbc7fa172617709dc7d4964dba7d3461b126f4 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockTestFactory.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockTestFactory.java
@@ -29,11 +29,12 @@ import java.util.Map;
 
 import com.thedeanda.lorem.LoremIpsum;
 
+import de.ozgcloud.vorgang.command.CommandTestFactory;
 import de.ozgcloud.vorgang.vorgang.Lock.LockBuilder;
 
 public class LockTestFactory {
 
-	public static final String CLIENT_NAME = LoremIpsum.getInstance().getFirstName() + "-Client";
+	public static final String CLIENT_NAME = CommandTestFactory.CREATED_BY_CLIENT;
 	public static final String REASON = LoremIpsum.getInstance().getWords(5);
 	public static final String LOCKED_SINCE_STR = ZonedDateTime.now().withNano(0).format(DateTimeFormatter.ISO_INSTANT);
 	public static final ZonedDateTime LOCKED_SINCE = ZonedDateTime.parse(LOCKED_SINCE_STR);
@@ -53,7 +54,6 @@ public class LockTestFactory {
 		return Map.of(
 				Lock.FIELD_CLIENT_NAME, CLIENT_NAME,
 				Lock.FIELD_LOCKED_SINCE, LOCKED_SINCE,
-				Lock.FIELD_REASON, REASON
-		);
+				Lock.FIELD_REASON, REASON);
 	}
 }
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java
index d57886aa60ea449c2003ecdbdf979614a259dc89..be162187880409f7b34a3329106ad843b1c4914c 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java
@@ -44,11 +44,13 @@ import org.springframework.context.ApplicationEventPublisher;
 import com.thedeanda.lorem.LoremIpsum;
 
 import de.ozgcloud.command.Command;
+import de.ozgcloud.command.CommandCreatedEvent;
 import de.ozgcloud.command.CommandExecutedEvent;
 import de.ozgcloud.command.CommandFailedEvent;
 import de.ozgcloud.command.CommandRevokeFailedEvent;
 import de.ozgcloud.command.CommandRevokedEvent;
 import de.ozgcloud.command.RevokeCommandEvent;
+import de.ozgcloud.command.VorgangUnlockedEvent;
 import de.ozgcloud.common.errorhandling.TechnicalException;
 import de.ozgcloud.vorgang.command.CommandCreatedEventTestFactory;
 import de.ozgcloud.vorgang.command.CommandService;
@@ -307,4 +309,52 @@ class VorgangEventListenerTest {
 			});
 		}
 	}
+
+	@Nested
+	class TestOnUnlockVorgang {
+
+		private final Command command = CommandTestFactory.create();
+
+		@Captor
+		private ArgumentCaptor<VorgangUnlockedEvent> vorgangUnlockedEventCaptor;
+		@Captor
+		private ArgumentCaptor<CommandFailedEvent> commandFailedEventCaptor;
+
+		@Test
+		void shouldUnlockVorgangOnUnlockVorgangOrder() {
+			onUnlockVorgang();
+
+			verify(service).unlockVorgang(command);
+		}
+
+		@Test
+		void shouldPublishVorgangUnlockedEvent() {
+			onUnlockVorgang();
+
+			verify(publisher).publishEvent(vorgangUnlockedEventCaptor.capture());
+			assertThat(vorgangUnlockedEventCaptor.getValue()).satisfies(event -> {
+				assertThat(event).isInstanceOf(VorgangUnlockedEvent.class);
+				assertThat(event.getCommand()).isEqualTo(command);
+			});
+
+		}
+
+		@Test
+		void shouldPublishCommandFailedEvent() {
+			var errorMessage = "error message";
+			doThrow(new RuntimeException(errorMessage)).when(service).unlockVorgang(command);
+
+			onUnlockVorgang();
+
+			verify(publisher).publishEvent(commandFailedEventCaptor.capture());
+			assertThat(commandFailedEventCaptor.getValue()).satisfies(event -> {
+				assertThat(event.getSource()).isEqualTo(CommandTestFactory.ID);
+				assertThat(event.getErrorMessage()).isEqualTo(errorMessage);
+			});
+		}
+
+		private void onUnlockVorgang() {
+			listener.onUnlockVorgang(new CommandCreatedEvent(command));
+		}
+	}
 }
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangRepositoryITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangRepositoryITCase.java
index 9d19e8a701453ad636c4458f45d9de1f30b2927b..65fd1a6bf226e3ddc4f5a8ba761f490e9f501a0c 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangRepositoryITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangRepositoryITCase.java
@@ -382,5 +382,57 @@ class VorgangRepositoryITCase {
 
 			assertThat(isLocked).isFalse();
 		}
+
+		@Test
+		void shouldReturnFalseAfterLockRemoved() {
+			var vorgang = mongoOperations.save(
+					VorgangTestFactory.createBuilder().id(null).version(0).header(VorgangHeadTestFactory.create()).build());
+			repository.removeLock(vorgang.getId(), 0);
+
+			var isLocked = repository.isVorgangLocked(vorgang.getId());
+
+			assertThat(isLocked).isFalse();
+		}
+	}
+
+	@Nested
+	class TestRemoveLock {
+
+		private final Vorgang vorgang = VorgangTestFactory.createBuilder()
+				.header(VorgangHeadTestFactory.create())
+				.build();
+
+		@BeforeEach
+		void persistVorgang() {
+			repository.save(vorgang);
+		}
+
+		@Test
+		void shouldRemoveLock() {
+			removeLock();
+
+			assertThat(getVorgang().getHeader().getLock()).isNull();
+		}
+
+		@Test
+		void shouldIncrementVersion() {
+			removeLock();
+
+			assertThat(getVorgang().getVersion()).isEqualTo(VorgangTestFactory.VERSION + 1);
+		}
+
+		private void removeLock() {
+			repository.removeLock(VorgangTestFactory.ID, VorgangTestFactory.VERSION);
+		}
+
+		@Test
+		void shouldThrowExceptionByCollision() {
+			assertThrows(ConcurrentModificationException.class,
+					() -> repository.removeLock(VorgangTestFactory.ID, VorgangTestFactory.VERSION + 1));
+		}
+
+		private Vorgang getVorgang() {
+			return mongoOperations.findById(VorgangTestFactory.ID, Vorgang.class);
+		}
 	}
 }
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java
index 5e4c2e4690780c92555b58237d9662f6dafe91c8..8cda2f7766d0e4a776f9b4de9fc1d716d1951a27 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java
@@ -24,6 +24,7 @@
 package de.ozgcloud.vorgang.vorgang;
 
 import static org.assertj.core.api.Assertions.*;
+import static org.assertj.core.api.InstanceOfAssertFactories.*;
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
@@ -352,7 +353,7 @@ class VorgangServiceTest {
 			void shouldThrowAccessDeniedException() {
 				when(vorgangAuthorizationService.authorizeByOrganisationseinheitenId(any(), any())).thenReturn(false);
 
-				assertThrows(AccessDeniedException.class, () -> service.getById(VorgangTestFactory.ID, FilterCriteriaTestFactory.create())); //NOSONAR
+				assertThrows(AccessDeniedException.class, () -> service.getById(VorgangTestFactory.ID, FilterCriteriaTestFactory.create())); // NOSONAR
 			}
 		}
 
@@ -586,7 +587,7 @@ class VorgangServiceTest {
 	@Nested
 	class TestBuildLockPatch {
 
-		 private final Command command = CommandTestFactory.createBuilder().bodyObject(Map.of(Lock.FIELD_REASON, LockTestFactory.REASON)).build();
+		private final Command command = CommandTestFactory.createBuilder().bodyObject(Map.of(Lock.FIELD_REASON, LockTestFactory.REASON)).build();
 
 		@Test
 		void shouldSetClientName() {
@@ -632,4 +633,131 @@ class VorgangServiceTest {
 			assertThat(result).isTrue();
 		}
 	}
+
+	@Nested
+	class TestUnlockVorgang {
+
+		private final Command command = CommandTestFactory.create();
+
+		@BeforeEach
+		void mock() {
+			doNothing().when(service).validateUnlockingClient(any());
+		}
+
+		@Test
+		void shouldCallValidateUnlockingClient() {
+			unlockVorgang();
+
+			verify(service).validateUnlockingClient(command);
+		}
+
+		@Test
+		void shouldCallRepository() {
+			unlockVorgang();
+
+			verify(repository).removeLock(VorgangTestFactory.ID, CommandTestFactory.RELATION_VERSION);
+		}
+
+		private void unlockVorgang() {
+			service.unlockVorgang(command);
+		}
+	}
+
+	@Nested
+	class TestValidateUnlockingClient {
+
+		private final Vorgang vorgang = VorgangTestFactory.createBuilder().header(VorgangHeadTestFactory.create()).build();
+		private final Command command = CommandTestFactory.create();
+
+		@Test
+		void shouldGetVorgangFromRepository() {
+			givenRepositoryReturnsVorgang();
+
+			validateUnlockingClient();
+
+			verify(repository).findById(VorgangTestFactory.ID);
+		}
+
+		@Test
+		void shouldThrowNotFoundException() {
+			when(repository.findById(VorgangTestFactory.ID)).thenReturn(Optional.empty());
+
+			assertThrows(NotFoundException.class, () -> validateUnlockingClient());
+		}
+
+		@Test
+		void shouldCallValidateClientName() {
+			givenRepositoryReturnsVorgang();
+
+			validateUnlockingClient();
+
+			verify(service).validateClientName(CommandTestFactory.CREATED_BY_CLIENT, Optional.of(VorgangHeadTestFactory.LOCK));
+		}
+
+		private void givenRepositoryReturnsVorgang() {
+			when(repository.findById(VorgangTestFactory.ID)).thenReturn(Optional.of(vorgang));
+		}
+
+		private void validateUnlockingClient() {
+			service.validateUnlockingClient(command);
+		}
+	}
+
+	@Nested
+	class TestValidateClientName {
+
+		private final Lock lock = LockTestFactory.create();
+
+		@Test
+		void shouldCallHasNoPermissionToUnlock() {
+			doReturn(false).when(service).hasNoPermissionToUnlock(any(), any());
+
+			validateClientName();
+
+			verify(service).hasNoPermissionToUnlock(CommandTestFactory.CREATED_BY_CLIENT, Optional.of(lock));
+		}
+
+		@Test
+		void shouldThrowAccessDeniedException() {
+			doReturn(true).when(service).hasNoPermissionToUnlock(any(), any());
+
+			assertThrows(AccessDeniedException.class, () -> validateClientName());
+		}
+
+		@Test
+		void shouldNotThrowException() {
+			doReturn(false).when(service).hasNoPermissionToUnlock(any(), any());
+
+			assertDoesNotThrow(() -> validateClientName());
+		}
+
+		private void validateClientName() {
+			service.validateClientName(CommandTestFactory.CREATED_BY_CLIENT, Optional.of(lock));
+		}
+	}
+
+	@Nested
+	class TestHasNoPermissionToUnlock {
+
+		@Test
+		void shouldReturnFalseIfLockEmpty() {
+			var result = service.hasNoPermissionToUnlock(CommandTestFactory.CREATED_BY_CLIENT, Optional.empty());
+
+			assertThat(result).isFalse();
+		}
+
+		@Test
+		void shouldReturnTrueIfLockPresentAndClientNameNotMatching() {
+			var result = service.hasNoPermissionToUnlock("wrong name", Optional.of(LockTestFactory.create()));
+
+			assertThat(result).isTrue();
+		}
+
+		@Test
+		void shouldReturnFalseIfLockPresentAndClientNameMatching() {
+			var result = service.hasNoPermissionToUnlock(LockTestFactory.CLIENT_NAME, Optional.of(LockTestFactory.create()));
+
+			assertThat(result).isFalse();
+		}
+	}
 }
\ No newline at end of file
diff --git a/vorgang-manager-utils/pom.xml b/vorgang-manager-utils/pom.xml
index 37bbe96a2714cd01208cd601a7f512cd6c6746ea..b37c7650b958b3fd8a90044d9e4c931bb921ca04 100644
--- a/vorgang-manager-utils/pom.xml
+++ b/vorgang-manager-utils/pom.xml
@@ -37,16 +37,16 @@
 	<groupId>de.ozgcloud.vorgang</groupId>
 	<artifactId>vorgang-manager-utils</artifactId>
 	<name>OZG-Cloud Vorgang Manager Utils</name>
-	<version>2.18.0-SNAPSHOT</version>
+	<version>2.19.0-SNAPSHOT</version>
 
 	<properties>
 		<maven-compiler-plugin.version>3.10.1</maven-compiler-plugin.version>
 		<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
-		
+
 		<maven-surefire-plugin.version>3.2.2</maven-surefire-plugin.version>
 		<maven-failsafe-plugin.version>3.2.2</maven-failsafe-plugin.version>
 		<lombok.version>1.18.34</lombok.version>
-		
+
 	</properties>
 
 	<dependencies>