diff --git a/apps/user_ldap/group_ldap.php b/apps/user_ldap/group_ldap.php
index 8a6084b6c8f997555a9c9bd672abba5758639963..e8d268d3df2848a680303a20449ccbb6bbef2687 100644
--- a/apps/user_ldap/group_ldap.php
+++ b/apps/user_ldap/group_ldap.php
@@ -34,6 +34,11 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
 	 */
 	protected $cachedGroupMembers = array();
 
+	/**
+	 * @var string[] $cachedGroupsByMember array of groups with uid as key
+	 */
+	protected $cachedGroupsByMember = array();
+
 	public function __construct(Access $access) {
 		parent::__construct($access);
 		$filter = $this->access->connection->ldapGroupFilter;
@@ -98,16 +103,28 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
 		}
 
 		//extra work if we don't get back user DNs
-		//TODO: this can be done with one LDAP query
 		if(strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid') {
 			$dns = array();
+			$filterParts = array();
+			$bytes = 0;
 			foreach($members as $mid) {
 				$filter = str_replace('%uid', $mid, $this->access->connection->ldapLoginFilter);
-				$ldap_users = $this->access->fetchListOfUsers($filter, 'dn');
-				if(count($ldap_users) < 1) {
-					continue;
+				$filterParts[] = $filter;
+				$bytes += strlen($filter);
+				if($bytes >= 9000000) {
+					// AD has a default input buffer of 10 MB, we do not want
+					// to take even the chance to exceed it
+					$filter = $this->access->combineFilterWithOr($filterParts);
+					$bytes = 0;
+					$filterParts = array();
+					$users = $this->access->fetchListOfUsers($filter, 'dn', count($filterParts));
+					$dns = array_merge($dns, $users);
 				}
-				$dns[] = $ldap_users[0];
+			}
+			if(count($filterParts) > 0) {
+				$filter = $this->access->combineFilterWithOr($filterParts);
+				$users = $this->access->fetchListOfUsers($filter, 'dn', count($filterParts));
+				$dns = array_merge($dns, $users);
 			}
 			$members = $dns;
 		}
@@ -316,8 +333,13 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
 			$uid = $userDN;
 		}
 
-		$groups = array_values($this->getGroupsByMember($uid));
-		$groups = $this->access->ownCloudGroupNames($groups);
+		if(isset($this->cachedGroupsByMember[$uid])) {
+			$groups = $this->cachedGroupsByMember[$uid];
+		} else {
+			$groups = array_values($this->getGroupsByMember($uid));
+			$groups = $this->access->ownCloudGroupNames($groups);
+			$this->cachedGroupsByMember[$uid] = $groups;
+		}
 
 		$primaryGroup = $this->getUserPrimaryGroup($userDN);
 		if($primaryGroup !== false) {
diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php
index 159b0d7300041e7c1e384d9a468fd8d0399a7137..44162e32d47044e598e1f4d537db5c853c369417 100644
--- a/apps/user_ldap/lib/access.php
+++ b/apps/user_ldap/lib/access.php
@@ -1359,7 +1359,7 @@ class Access extends LDAPUtility implements user\IUserTools {
 	 * @param string[] $bases array containing the allowed base DN or DNs
 	 * @return bool
 	 */
-	private function isDNPartOfBase($dn, $bases) {
+	public function isDNPartOfBase($dn, $bases) {
 		$belongsToBase = false;
 		$bases = $this->sanitizeDN($bases);
 
diff --git a/lib/private/group/manager.php b/lib/private/group/manager.php
index 33a1904dddf0b6320364ee8ca891a2e4abb72637..417be79ab30af40beed1cf73dc2684be0f83daa6 100644
--- a/lib/private/group/manager.php
+++ b/lib/private/group/manager.php
@@ -223,10 +223,9 @@ class Manager extends PublicEmitter implements IGroupManager {
 		if(!empty($search)) {
 			// only user backends have the capability to do a complex search for users
 			$searchOffset = 0;
+			$searchLimit = $limit * 100;
 			if($limit === -1) {
-				$searchLimit = $group->count('');
-			} else {
-				$searchLimit = $limit * 2;
+				$searchLimit = 500;
 			}
 
 			do {