diff --git a/core/Migrations/Version15000Date20180917092725.php b/core/Migrations/Version16000Date20190207141427.php
similarity index 73%
rename from core/Migrations/Version15000Date20180917092725.php
rename to core/Migrations/Version16000Date20190207141427.php
index 1bcc6382745404c86ca874cdca776abe3160eda8..44e09a8463b22d484adbc20123782a3e7dd216aa 100644
--- a/core/Migrations/Version15000Date20180917092725.php
+++ b/core/Migrations/Version16000Date20190207141427.php
@@ -28,7 +28,7 @@ use OCP\DB\ISchemaWrapper;
 use OCP\Migration\SimpleMigrationStep;
 use OCP\Migration\IOutput;
 
-class Version15000Date20180917092725 extends SimpleMigrationStep {
+class Version16000Date20190207141427 extends SimpleMigrationStep {
 
 
 	/**
@@ -74,6 +74,30 @@ class Version15000Date20180917092725 extends SimpleMigrationStep {
 			$table->addUniqueIndex(['collection_id', 'resource_type', 'resource_id'], 'collres_unique_res');
 		}
 
+		if (!$schema->hasTable('collres_accesscache')) {
+			$table = $schema->createTable('collres_accesscache');
+
+			$table->addColumn('user_id', Type::STRING, [
+				'notnull' => true,
+				'length' => 64,
+			]);
+			$table->addColumn('collection_id', Type::BIGINT, [
+				'notnull' => false,
+			]);
+			$table->addColumn('resource_id', Type::STRING, [
+				'notnull' => false,
+				'length' => 64,
+			]);
+			$table->addColumn('access', Type::SMALLINT, [
+				'notnull' => true,
+				'default' => 0,
+			]);
+
+			$table->addUniqueIndex(['user_id', 'collection_id', 'resource_id'], 'collres_unique_user');
+			$table->addIndex(['user_id', 'resource_id'], 'collres_user_res');
+			$table->addIndex(['user_id', 'collection_id'], 'collres_user_coll');
+		}
+
 		return $schema;
 	}
 
diff --git a/lib/private/Collaboration/Resources/Collection.php b/lib/private/Collaboration/Resources/Collection.php
index 5770e8918fd660b73bd5038ee7d04144c7382acc..c538580b8f8330a0eb09a32cba120de7f1bd6328 100644
--- a/lib/private/Collaboration/Resources/Collection.php
+++ b/lib/private/Collaboration/Resources/Collection.php
@@ -46,6 +46,9 @@ class Collection implements ICollection {
 	/** @var string */
 	protected $name;
 
+	/** @var bool|null */
+	protected $access;
+
 	/** @var IResource[] */
 	protected $resources;
 
@@ -53,12 +56,14 @@ class Collection implements ICollection {
 		IManager $manager,
 		IDBConnection $connection,
 		int $id,
-		string $name
+		string $name,
+		?bool $access
 	) {
 		$this->manager = $manager;
 		$this->connection = $connection;
 		$this->id = $id;
 		$this->name = $name;
+		$this->access = $access;
 		$this->resources = [];
 	}
 
@@ -161,13 +166,16 @@ class Collection implements ICollection {
 	 * @since 16.0.0
 	 */
 	public function canAccess(IUser $user = null): bool {
-		foreach ($this->getResources() as $resource) {
-			if ($resource->canAccess($user)) {
-				return true;
+		if ($this->access === null) {
+			$this->access = false;
+			foreach ($this->getResources() as $resource) {
+				if ($resource->canAccess($user)) {
+					$this->access = true;
+				}
 			}
 		}
 
-		return false;
+		return $this->access;
 	}
 
 	protected function isSameResource(IResource $resource1, IResource $resource2): bool {
diff --git a/lib/private/Collaboration/Resources/Manager.php b/lib/private/Collaboration/Resources/Manager.php
index 55274432d76cc613ac14148478ca6fd6f8235468..ae42f272c052b986b9e69c944a35e8a2e420a347 100644
--- a/lib/private/Collaboration/Resources/Manager.php
+++ b/lib/private/Collaboration/Resources/Manager.php
@@ -193,6 +193,85 @@ class Manager implements IManager {
 		return false;
 	}
 
+	public function cacheAccessForResource(IResource $resource, ?IUser $user, bool $access): void {
+		$query = $this->connection->getQueryBuilder();
+		$userId = $user instanceof IUser ? $user->getUID() : '';
+
+		$query->insert('collres_accesscache')
+			->values([
+				'user_id' => $query->createNamedParameter($userId),
+				'resource_id' => $query->createNamedParameter($resource->getId()),
+				'access' => $query->createNamedParameter($access),
+			]);
+		$query->execute();
+	}
+
+	public function cacheAccessForCollection(ICollection $collection, ?IUser $user, bool $access): void {
+		$query = $this->connection->getQueryBuilder();
+		$userId = $user instanceof IUser ? $user->getUID() : '';
+
+		$query->insert('collres_accesscache')
+			->values([
+				'user_id' => $query->createNamedParameter($userId),
+				'collection_id' => $query->createNamedParameter($collection->getId()),
+				'access' => $query->createNamedParameter($access),
+			]);
+		$query->execute();
+	}
+
+	public function invalidateAccessCacheForUser(?IUser $user): void {
+		$query = $this->connection->getQueryBuilder();
+		$userId = $user instanceof IUser ? $user->getUID() : '';
+
+		$query->delete('collres_accesscache')
+			->where($query->expr()->eq('user_id', $query->createNamedParameter($userId)));
+		$query->execute();
+	}
+
+	public function invalidateAccessCacheForResource(IResource $resource): void {
+		$query = $this->connection->getQueryBuilder();
+
+		$query->delete('collres_accesscache')
+			->where($query->expr()->eq('resource_id', $query->createNamedParameter($resource->getId())));
+		$query->execute();
+
+		foreach ($resource->getCollections() as $collection) {
+			$this->invalidateAccessCacheForCollection($collection);
+		}
+	}
+
+	protected function invalidateAccessCacheForCollection(ICollection $collection): void {
+		$query = $this->connection->getQueryBuilder();
+
+		$query->delete('collres_accesscache')
+			->where($query->expr()->eq('collection_id', $query->createNamedParameter($collection->getId())));
+		$query->execute();
+	}
+
+	public function invalidateAccessCacheForResourceByUser(IResource $resource, ?IUser $user): void {
+		$query = $this->connection->getQueryBuilder();
+		$userId = $user instanceof IUser ? $user->getUID() : '';
+
+		$query->delete('collres_accesscache')
+			->where($query->expr()->eq('resource_id', $query->createNamedParameter($resource->getId())))
+			->andWhere($query->expr()->eq('user_id', $query->createNamedParameter($userId)));
+		$query->execute();
+
+		foreach ($resource->getCollections() as $collection) {
+			$this->invalidateAccessCacheForCollectionByUser($collection, $user);
+		}
+	}
+
+	protected function invalidateAccessCacheForCollectionByUser(ICollection $collection, ?IUser $user): void {
+		$query = $this->connection->getQueryBuilder();
+		$userId = $user instanceof IUser ? $user->getUID() : '';
+
+		$query->delete('collres_accesscache')
+			->where($query->expr()->eq('collection_id', $query->createNamedParameter($collection->getId())))
+			->andWhere($query->expr()->eq('user_id', $query->createNamedParameter($userId)));
+		$query->execute();
+	}
+
 	/**
 	 * @param IProvider $provider
 	 */
diff --git a/lib/private/Collaboration/Resources/Resource.php b/lib/private/Collaboration/Resources/Resource.php
index c31843bdd06033246c4a889ab22e3d1564cc6ce3..bfc63fefdfc897de2f7d357ed6e170e5b016f861 100644
--- a/lib/private/Collaboration/Resources/Resource.php
+++ b/lib/private/Collaboration/Resources/Resource.php
@@ -26,7 +26,6 @@ namespace OC\Collaboration\Resources;
 use OCP\Collaboration\Resources\ICollection;
 use OCP\Collaboration\Resources\IManager;
 use OCP\Collaboration\Resources\IResource;
-use OCP\Collaboration\Resources\ResourceException;
 use OCP\IDBConnection;
 use OCP\IUser;
 
@@ -44,6 +43,9 @@ class Resource implements IResource {
 	/** @var string */
 	protected $id;
 
+	/** @var bool|null */
+	protected $access;
+
 	/** @var string|null */
 	protected $name;
 
@@ -57,12 +59,14 @@ class Resource implements IResource {
 		IManager $manager,
 		IDBConnection $connection,
 		string $type,
-		string $id
+		string $id,
+		?bool $access
 	) {
 		$this->manager = $manager;
 		$this->connection = $connection;
 		$this->type = $type;
 		$this->id = $id;
+		$this->access = $access;
 	}
 
 	/**
@@ -122,7 +126,10 @@ class Resource implements IResource {
 	 * @since 16.0.0
 	 */
 	public function canAccess(IUser $user = null): bool {
-		return $this->manager->canAccess($this, $user);
+		if ($this->access === null) {
+			$this->access = $this->manager->canAccess($this, $user);
+		}
+		return $this->access;
 	}
 
 	/**