diff --git a/apps/federatedfilesharing/lib/federatedshareprovider.php b/apps/federatedfilesharing/lib/federatedshareprovider.php
index e54ce08fb04ce860708c2d108b44409f22fd4ff2..a450b420cf47ffbea894fa6d5acf253cd36a4f25 100644
--- a/apps/federatedfilesharing/lib/federatedshareprovider.php
+++ b/apps/federatedfilesharing/lib/federatedshareprovider.php
@@ -563,4 +563,21 @@ class FederatedShareProvider implements IShareProvider {
 		return $nodes[0];
 	}
 
+	/**
+	 * A user is deleted from the system
+	 * So clean up the relevant shares.
+	 *
+	 * @param string $uid
+	 * @param int $shareType
+	 */
+	public function userDeleted($uid, $shareType) {
+		//TODO: probabaly a good idea to send unshare info to remote servers
+
+		$qb = $this->dbConnection->getQueryBuilder();
+
+		$qb->delete('share')
+			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE)))
+			->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
+			->execute();
+	}
 }
diff --git a/apps/federatedfilesharing/tests/federatedshareprovidertest.php b/apps/federatedfilesharing/tests/federatedshareprovidertest.php
index dedd6767b49c0462745038c832ec90b6a92dd04c..92e9f10c3cd2218bec459aae804a4fdb9add05a6 100644
--- a/apps/federatedfilesharing/tests/federatedshareprovidertest.php
+++ b/apps/federatedfilesharing/tests/federatedshareprovidertest.php
@@ -462,4 +462,52 @@ class FederatedShareProviderTest extends TestCase {
 		$this->assertCount(1, $shares);
 		$this->assertEquals('user2@server.com', $shares[0]->getSharedWith());
 	}
+
+	public function dataDeleteUser() {
+		return [
+			['a', 'b', 'c', 'a', true],
+			['a', 'b', 'c', 'b', false],
+			// The recipient is non local.
+			['a', 'b', 'c', 'c', false],
+			['a', 'b', 'c', 'd', false],
+		];
+	}
+
+	/**
+	 * @dataProvider dataDeleteUser
+	 *
+	 * @param string $owner The owner of the share (uid)
+	 * @param string $initiator The initiator of the share (uid)
+	 * @param string $recipient The recipient of the share (uid/gid/pass)
+	 * @param string $deletedUser The user that is deleted
+	 * @param bool $rowDeleted Is the row deleted in this setup
+	 */
+	public function testDeleteUser($owner, $initiator, $recipient, $deletedUser, $rowDeleted) {
+		$qb = $this->connection->getQueryBuilder();
+		$qb->insert('share')
+			->setValue('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE))
+			->setValue('uid_owner', $qb->createNamedParameter($owner))
+			->setValue('uid_initiator', $qb->createNamedParameter($initiator))
+			->setValue('share_with', $qb->createNamedParameter($recipient))
+			->setValue('item_type', $qb->createNamedParameter('file'))
+			->setValue('item_source', $qb->createNamedParameter(42))
+			->setValue('file_source', $qb->createNamedParameter(42))
+			->execute();
+
+		$id = $qb->getLastInsertId();
+
+		$this->provider->userDeleted($deletedUser, \OCP\Share::SHARE_TYPE_REMOTE);
+
+		$qb = $this->connection->getQueryBuilder();
+		$qb->select('*')
+			->from('share')
+			->where(
+				$qb->expr()->eq('id', $qb->createNamedParameter($id))
+			);
+		$cursor = $qb->execute();
+		$data = $cursor->fetchAll();
+		$cursor->closeCursor();
+
+		$this->assertCount($rowDeleted ? 0 : 1, $data);
+	}
 }
diff --git a/lib/base.php b/lib/base.php
index 706322fb54276e07b3e6a089c0fca80d9a74bf27..a76edb1192a012c7186cf2d59617c6d5754ad08a 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -777,7 +777,7 @@ class OC {
 	 */
 	public static function registerShareHooks() {
 		if (\OC::$server->getSystemConfig()->getValue('installed')) {
-			OC_Hook::connect('OC_User', 'post_deleteUser', 'OC\Share\Hooks', 'post_deleteUser');
+			OC_Hook::connect('OC_User', 'post_deleteUser', 'OC\Share20\Hooks', 'post_deleteUser');
 			OC_Hook::connect('OC_User', 'post_addToGroup', 'OC\Share\Hooks', 'post_addToGroup');
 			OC_Hook::connect('OC_Group', 'pre_addToGroup', 'OC\Share\Hooks', 'pre_addToGroup');
 			OC_Hook::connect('OC_User', 'post_removeFromGroup', 'OC\Share\Hooks', 'post_removeFromGroup');
diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php
index f6171f87992945768e3caa761b69166fdaf6e8c7..370655f83154fe3405b466e4e7a4faa7170aaeaa 100644
--- a/lib/private/Share20/DefaultShareProvider.php
+++ b/lib/private/Share20/DefaultShareProvider.php
@@ -28,7 +28,6 @@ use OC\Share20\Exception\ProviderException;
 use OCP\Share\Exceptions\ShareNotFound;
 use OC\Share20\Exception\BackendError;
 use OCP\DB\QueryBuilder\IQueryBuilder;
-use OCP\Files\NotFoundException;
 use OCP\IGroup;
 use OCP\IGroupManager;
 use OCP\IUserManager;
@@ -804,4 +803,68 @@ class DefaultShareProvider implements IShareProvider {
 		return $share;
 	}
 
+	/**
+	 * A user is deleted from the system
+	 * So clean up the relevant shares.
+	 *
+	 * @param string $uid
+	 * @param int $shareType
+	 */
+	public function userDeleted($uid, $shareType) {
+		$qb = $this->dbConn->getQueryBuilder();
+
+		$qb->delete('share');
+
+		if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
+			/*
+			 * Delete all user shares that are owned by this user
+			 * or that are received by this user
+			 */
+
+			$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)));
+
+			$qb->andWhere(
+				$qb->expr()->orX(
+					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)),
+					$qb->expr()->eq('share_with', $qb->createNamedParameter($uid))
+				)
+			);
+		} else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
+			/*
+			 * Delete all group shares that are owned by this user
+			 * Or special user group shares that are received by this user
+			 */
+			$qb->where(
+				$qb->expr()->andX(
+					$qb->expr()->orX(
+						$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)),
+						$qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP))
+					),
+					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid))
+				)
+			);
+
+			$qb->orWhere(
+				$qb->expr()->andX(
+					$qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)),
+					$qb->expr()->eq('share_with', $qb->createNamedParameter($uid))
+				)
+			);
+		} else if ($shareType === \OCP\Share::SHARE_TYPE_LINK) {
+			/*
+			 * Delete all link shares owned by this user.
+			 * And all link shares initiated by this user (until #22327 is in)
+			 */
+			$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_LINK)));
+
+			$qb->andWhere(
+				$qb->expr()->orX(
+					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)),
+					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($uid))
+				)
+			);
+		}
+
+		$qb->execute();
+	}
 }
diff --git a/lib/private/Share20/Hooks.php b/lib/private/Share20/Hooks.php
new file mode 100644
index 0000000000000000000000000000000000000000..93669974b28178c1ff273b3cefd1df2c72192ca9
--- /dev/null
+++ b/lib/private/Share20/Hooks.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * @author Roeland Jago Douma <rullzer@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OC\Share20;
+
+class Hooks {
+	public static function post_deleteUser($arguments) {
+		\OC::$server->getShareManager()->userDeleted($arguments['uid']);
+	}
+}
diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php
index 1c9d4d82277f6f76f80af8a4a3e07d4f0ac9b65f..6c665f7e133c015a98ff792d7dad0276e860b476 100644
--- a/lib/private/Share20/Manager.php
+++ b/lib/private/Share20/Manager.php
@@ -1018,6 +1018,18 @@ class Manager implements IManager {
 		return true;
 	}
 
+	/**
+	 * @inheritdoc
+	 */
+	public function userDeleted($uid) {
+		$types = [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE];
+
+		foreach ($types as $type) {
+			$provider = $this->factory->getProviderForType($type);
+			$provider->userDeleted($uid, $type);
+		}
+	}
+
 	/**
 	 * Get access list to a path. This means
 	 * all the users and groups that can access a given path.
diff --git a/lib/private/share/hooks.php b/lib/private/share/hooks.php
index 750486ba80fd8e1c133e010c31c7e2e7cfd9db78..dae273eefb8f17a917fead1bcedec632b2955b57 100644
--- a/lib/private/share/hooks.php
+++ b/lib/private/share/hooks.php
@@ -32,24 +32,6 @@ class Hooks extends \OC\Share\Constants {
 	 */
 	private static $updateTargets = array();
 
-	/**
-	 * Function that is called after a user is deleted. Cleans up the shares of that user.
-	 * @param array $arguments
-	 */
-	public static function post_deleteUser($arguments) {
-		// Delete any items shared with the deleted user
-		$query = \OC_DB::prepare('DELETE FROM `*PREFIX*share`'
-			.' WHERE `share_with` = ? AND (`share_type` = ? OR `share_type` = ?)');
-		$query->execute(array($arguments['uid'], self::SHARE_TYPE_USER, self::$shareTypeGroupUserUnique));
-		// Delete any items the deleted user shared
-		$query = \OC_DB::prepare('SELECT `id` FROM `*PREFIX*share` WHERE `uid_owner` = ?');
-		$result = $query->execute(array($arguments['uid']));
-		while ($item = $result->fetchRow()) {
-			Helper::delete($item['id']);
-		}
-	}
-
-
 	/**
 	 * Function that is called before a user is added to a group.
 	 * check if we need to create a unique target for the user
diff --git a/lib/public/Share/IManager.php b/lib/public/Share/IManager.php
index 64e5b554de989e101085d9a01a811e928e530bec..e3780ac070c600c7198287c61ca05126dcbd2b41 100644
--- a/lib/public/Share/IManager.php
+++ b/lib/public/Share/IManager.php
@@ -149,6 +149,17 @@ interface IManager {
 	 */
 	public function checkPassword(IShare $share, $password);
 
+	/**
+	 * The user with UID is deleted.
+	 * All share providers have to cleanup the shares with this user as well
+	 * as shares owned by this user.
+	 * Shares only initiated by this user are fine.
+	 *
+	 * @param string $uid
+	 * @since 9.1.0
+	 */
+	public function userDeleted($uid);
+
 	/**
 	 * Instantiates a new share object. This is to be passed to
 	 * createShare.
diff --git a/lib/public/Share/IShareProvider.php b/lib/public/Share/IShareProvider.php
index d00b9da7b59f18eaf54b66cd68e33fd2390fba8b..e201ba81ebc8ea4edfe936d60dea1b44b876ddeb 100644
--- a/lib/public/Share/IShareProvider.php
+++ b/lib/public/Share/IShareProvider.php
@@ -146,4 +146,14 @@ interface IShareProvider {
 	 * @since 9.0.0
 	 */
 	public function getShareByToken($token);
+
+	/**
+	 * A user is deleted from the system
+	 * So clean up the relevant shares.
+	 *
+	 * @param string $uid
+	 * @param int $shareType
+	 * @since 9.1.0
+	 */
+	public function userDeleted($uid, $shareType);
 }
diff --git a/tests/lib/share20/defaultshareprovidertest.php b/tests/lib/share20/defaultshareprovidertest.php
index 8d8ae8d4809f86b35622084fed46e3a045b78cd3..d8b594519b6369026205ad3ddea586251865dbea 100644
--- a/tests/lib/share20/defaultshareprovidertest.php
+++ b/tests/lib/share20/defaultshareprovidertest.php
@@ -1872,4 +1872,131 @@ class DefaultShareProviderTest extends \Test\TestCase {
 		$share = $this->provider->getShareById($id, 'user0');
 		$this->assertSame('/ultraNewTarget', $share->getTarget());
 	}
+
+	public function dataDeleteUser() {
+		return [
+			[\OCP\Share::SHARE_TYPE_USER, 'a', 'b', 'c', 'a', true],
+			[\OCP\Share::SHARE_TYPE_USER, 'a', 'b', 'c', 'b', false],
+			[\OCP\Share::SHARE_TYPE_USER, 'a', 'b', 'c', 'c', true],
+			[\OCP\Share::SHARE_TYPE_USER, 'a', 'b', 'c', 'd', false],
+			[\OCP\Share::SHARE_TYPE_GROUP, 'a', 'b', 'c', 'a', true],
+			[\OCP\Share::SHARE_TYPE_GROUP, 'a', 'b', 'c', 'b', false],
+			// The group c is still valid but user c is deleted so group share stays
+			[\OCP\Share::SHARE_TYPE_GROUP, 'a', 'b', 'c', 'c', false],
+			[\OCP\Share::SHARE_TYPE_GROUP, 'a', 'b', 'c', 'd', false],
+			[\OCP\Share::SHARE_TYPE_LINK, 'a', 'b', 'c', 'a', true],
+			// To avoid invisible link shares delete initiated link shares as well (see #22327)
+			[\OCP\Share::SHARE_TYPE_LINK, 'a', 'b', 'c', 'b', true],
+			[\OCP\Share::SHARE_TYPE_LINK, 'a', 'b', 'c', 'c', false],
+			[\OCP\Share::SHARE_TYPE_LINK, 'a', 'b', 'c', 'd', false],
+		];
+	}
+
+	/**
+	 * @dataProvider dataDeleteUser
+	 *
+	 * @param int $type The shareType (user/group/link)
+	 * @param string $owner The owner of the share (uid)
+	 * @param string $initiator The initiator of the share (uid)
+	 * @param string $recipient The recipient of the share (uid/gid/pass)
+	 * @param string $deletedUser The user that is deleted
+	 * @param bool $rowDeleted Is the row deleted in this setup
+	 */
+	public function testDeleteUser($type, $owner, $initiator, $recipient, $deletedUser, $rowDeleted) {
+		$qb = $this->dbConn->getQueryBuilder();
+		$qb->insert('share')
+			->setValue('share_type', $qb->createNamedParameter($type))
+			->setValue('uid_owner', $qb->createNamedParameter($owner))
+			->setValue('uid_initiator', $qb->createNamedParameter($initiator))
+			->setValue('share_with', $qb->createNamedParameter($recipient))
+			->setValue('item_type', $qb->createNamedParameter('file'))
+			->setValue('item_source', $qb->createNamedParameter(42))
+			->setValue('file_source', $qb->createNamedParameter(42))
+			->execute();
+
+		$id = $qb->getLastInsertId();
+
+		$this->provider->userDeleted($deletedUser, $type);
+
+		$qb = $this->dbConn->getQueryBuilder();
+		$qb->select('*')
+			->from('share')
+			->where(
+				$qb->expr()->eq('id', $qb->createNamedParameter($id))
+			);
+		$cursor = $qb->execute();
+		$data = $cursor->fetchAll();
+		$cursor->closeCursor();
+
+		$this->assertCount($rowDeleted ? 0 : 1, $data);
+	}
+
+	public function dataDeleteUserGroup() {
+		return [
+			['a', 'b', 'c', 'a', true, true],
+			['a', 'b', 'c', 'b', false, false],
+			['a', 'b', 'c', 'c', false, true],
+			['a', 'b', 'c', 'd', false, false],
+		];
+	}
+
+	/**
+	 * @dataProvider dataDeleteUserGroup
+	 *
+	 * @param string $owner The owner of the share (uid)
+	 * @param string $initiator The initiator of the share (uid)
+	 * @param string $recipient The recipient of the usergroup share (uid)
+	 * @param string $deletedUser The user that is deleted
+	 * @param bool $groupShareDeleted
+	 * @param bool $userGroupShareDeleted
+	 */
+	public function testDeleteUserGroup($owner, $initiator, $recipient, $deletedUser, $groupShareDeleted, $userGroupShareDeleted) {
+		$qb = $this->dbConn->getQueryBuilder();
+		$qb->insert('share')
+			->setValue('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP))
+			->setValue('uid_owner', $qb->createNamedParameter($owner))
+			->setValue('uid_initiator', $qb->createNamedParameter($initiator))
+			->setValue('share_with', $qb->createNamedParameter('group'))
+			->setValue('item_type', $qb->createNamedParameter('file'))
+			->setValue('item_source', $qb->createNamedParameter(42))
+			->setValue('file_source', $qb->createNamedParameter(42))
+			->execute();
+		$groupId = $qb->getLastInsertId();
+
+		$qb = $this->dbConn->getQueryBuilder();
+		$qb->insert('share')
+			->setValue('share_type', $qb->createNamedParameter(2))
+			->setValue('uid_owner', $qb->createNamedParameter($owner))
+			->setValue('uid_initiator', $qb->createNamedParameter($initiator))
+			->setValue('share_with', $qb->createNamedParameter($recipient))
+			->setValue('item_type', $qb->createNamedParameter('file'))
+			->setValue('item_source', $qb->createNamedParameter(42))
+			->setValue('file_source', $qb->createNamedParameter(42))
+			->execute();
+		$userGroupId = $qb->getLastInsertId();
+
+		$this->provider->userDeleted($deletedUser, \OCP\Share::SHARE_TYPE_GROUP);
+
+		$qb = $this->dbConn->getQueryBuilder();
+		$qb->select('*')
+			->from('share')
+			->where(
+				$qb->expr()->eq('id', $qb->createNamedParameter($userGroupId))
+			);
+		$cursor = $qb->execute();
+		$data = $cursor->fetchAll();
+		$cursor->closeCursor();
+		$this->assertCount($userGroupShareDeleted ? 0 : 1, $data);
+
+		$qb = $this->dbConn->getQueryBuilder();
+		$qb->select('*')
+			->from('share')
+			->where(
+				$qb->expr()->eq('id', $qb->createNamedParameter($groupId))
+			);
+		$cursor = $qb->execute();
+		$data = $cursor->fetchAll();
+		$cursor->closeCursor();
+		$this->assertCount($groupShareDeleted ? 0 : 1, $data);
+	}
 }