diff --git a/.htaccess b/.htaccess
index 81dae47a34d973047dead62e354849285f179434..190b414558b29b082a387509cc586418299ac843 100644
--- a/.htaccess
+++ b/.htaccess
@@ -23,7 +23,7 @@
   <FilesMatch "\.(css|js|svg|gif)$">
     Header set Cache-Control "max-age=15778463"
   </FilesMatch>
-  
+
   # Let browsers cache WOFF files for a week
   <FilesMatch "\.woff$">
     Header set Cache-Control "max-age=604800"
diff --git a/lib/private/DB/Connection.php b/lib/private/DB/Connection.php
index b9ef447b74b54b67a34ff0a3aea114c1b0cf2fc3..8a8a2f100ef05b19ab44f2d5b8f82ff0c6968b94 100644
--- a/lib/private/DB/Connection.php
+++ b/lib/private/DB/Connection.php
@@ -401,7 +401,7 @@ class Connection extends \Doctrine\DBAL\Connection implements IDBConnection {
 	}
 
 	/**
-	 * Espace a parameter to be used in a LIKE query
+	 * Escape a parameter to be used in a LIKE query
 	 *
 	 * @param string $param
 	 * @return string
diff --git a/lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php b/lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php
index a32ae4a1827d056096b3e383430fc83c01946575..154f2447c77a56aac67f2dcf7c044bdce1ed9a6a 100644
--- a/lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php
+++ b/lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php
@@ -26,6 +26,7 @@ namespace OC\DB\QueryBuilder\ExpressionBuilder;
 
 use Doctrine\DBAL\Query\Expression\ExpressionBuilder as DoctrineExpressionBuilder;
 use OC\DB\QueryBuilder\CompositeExpression;
+use OC\DB\QueryBuilder\FunctionBuilder\FunctionBuilder;
 use OC\DB\QueryBuilder\Literal;
 use OC\DB\QueryBuilder\QueryFunction;
 use OC\DB\QueryBuilder\QuoteHelper;
@@ -45,15 +46,20 @@ class ExpressionBuilder implements IExpressionBuilder {
 	/** @var IDBConnection */
 	protected $connection;
 
+	/** @var FunctionBuilder */
+	protected $functionBuilder;
+
 	/**
 	 * Initializes a new <tt>ExpressionBuilder</tt>.
 	 *
-	 * @param \OCP\IDBConnection $connection
+	 * @param IDBConnection $connection
+	 * @param IQueryBuilder $queryBuilder
 	 */
-	public function __construct(IDBConnection $connection) {
+	public function __construct(IDBConnection $connection, IQueryBuilder $queryBuilder) {
 		$this->connection = $connection;
 		$this->helper = new QuoteHelper();
 		$this->expressionBuilder = new DoctrineExpressionBuilder($connection);
+		$this->functionBuilder = $queryBuilder->func();
 	}
 
 	/**
@@ -298,9 +304,7 @@ class ExpressionBuilder implements IExpressionBuilder {
 	 * @since 9.0.0
 	 */
 	public function iLike($x, $y, $type = null) {
-		$x = $this->helper->quoteColumnName($x);
-		$y = $this->helper->quoteColumnName($y);
-		return $this->expressionBuilder->comparison("LOWER($x)", 'LIKE', "LOWER($y)");
+		return $this->expressionBuilder->like($this->functionBuilder->lower($x), $this->functionBuilder->lower($y));
 	}
 
 	/**
diff --git a/lib/private/DB/QueryBuilder/ExpressionBuilder/MySqlExpressionBuilder.php b/lib/private/DB/QueryBuilder/ExpressionBuilder/MySqlExpressionBuilder.php
index 17f7fd5aa4722217522978be4e6405951d3aa9d2..aa7ef8e70be66008082d07c21aca2a5995d32223 100644
--- a/lib/private/DB/QueryBuilder/ExpressionBuilder/MySqlExpressionBuilder.php
+++ b/lib/private/DB/QueryBuilder/ExpressionBuilder/MySqlExpressionBuilder.php
@@ -25,6 +25,7 @@ namespace OC\DB\QueryBuilder\ExpressionBuilder;
 
 
 use OC\DB\Connection;
+use OCP\DB\QueryBuilder\IQueryBuilder;
 use OCP\IDBConnection;
 
 class MySqlExpressionBuilder extends ExpressionBuilder {
@@ -34,9 +35,10 @@ class MySqlExpressionBuilder extends ExpressionBuilder {
 
 	/**
 	 * @param \OCP\IDBConnection|Connection $connection
+	 * @param IQueryBuilder $queryBuilder
 	 */
-	public function __construct(IDBConnection $connection) {
-		parent::__construct($connection);
+	public function __construct(IDBConnection $connection, IQueryBuilder $queryBuilder) {
+		parent::__construct($connection, $queryBuilder);
 
 		$params = $connection->getParams();
 		$this->charset = isset($params['charset']) ? $params['charset'] : 'utf8';
diff --git a/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php b/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php
index 14d8ad33e40b2a3912329d2ddb2ecb1c2705bf5c..d9e8a1279cc0ea73cef5d50c4f6872d9db83a8e7 100644
--- a/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php
+++ b/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php
@@ -31,4 +31,8 @@ class SqliteExpressionBuilder extends ExpressionBuilder {
 	public function like($x, $y, $type = null) {
 		return parent::like($x, $y, $type) . " ESCAPE '\\'";
 	}
+
+	public function iLike($x, $y, $type = null) {
+		return $this->like($this->functionBuilder->lower($x), $this->functionBuilder->lower($y), $type);
+	}
 }
diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php
index 2789b8cb356febe0fb47023ae77d0d578767a53a..1d7453063519c2fab443b66571b6a8006afceda2 100644
--- a/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php
+++ b/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php
@@ -59,4 +59,8 @@ class FunctionBuilder implements IFunctionBuilder {
 	public function sum($field) {
 		return new QueryFunction('SUM(' . $this->helper->quoteColumnName($field) . ')');
 	}
+
+	public function lower($field) {
+		return new QueryFunction('LOWER(' . $this->helper->quoteColumnName($field) . ')');
+	}
 }
diff --git a/lib/private/DB/QueryBuilder/QueryBuilder.php b/lib/private/DB/QueryBuilder/QueryBuilder.php
index 58be4b43255fe5d249fa93803122a47b6b815cab..d6f8bb48acde440024f247edeab9c0ebfc852c63 100644
--- a/lib/private/DB/QueryBuilder/QueryBuilder.php
+++ b/lib/private/DB/QueryBuilder/QueryBuilder.php
@@ -112,15 +112,15 @@ class QueryBuilder implements IQueryBuilder {
 	 */
 	public function expr() {
 		if ($this->connection instanceof OracleConnection) {
-			return new OCIExpressionBuilder($this->connection);
+			return new OCIExpressionBuilder($this->connection, $this);
 		} else if ($this->connection->getDatabasePlatform() instanceof PostgreSqlPlatform) {
-			return new PgSqlExpressionBuilder($this->connection);
+			return new PgSqlExpressionBuilder($this->connection, $this);
 		} else if ($this->connection->getDatabasePlatform() instanceof MySqlPlatform) {
-			return new MySqlExpressionBuilder($this->connection);
+			return new MySqlExpressionBuilder($this->connection, $this);
 		} else if ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) {
-			return new SqliteExpressionBuilder($this->connection);
+			return new SqliteExpressionBuilder($this->connection, $this);
 		} else {
-			return new ExpressionBuilder($this->connection);
+			return new ExpressionBuilder($this->connection, $this);
 		}
 	}
 
diff --git a/lib/private/User/Database.php b/lib/private/User/Database.php
index 471ff1f45ae7f63affae7b7c6f8dc99c00b6e594..6e44c9022867191ee814f8f73b07aa1495c51559 100644
--- a/lib/private/User/Database.php
+++ b/lib/private/User/Database.php
@@ -40,6 +40,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>
  *
  */
+
 /*
  *
  * The following SQL statement is just a help for developers and will not be
@@ -56,6 +57,7 @@
 namespace OC\User;
 
 use OC\Cache\CappedMemoryCache;
+use OC\DB\QueryBuilder\Literal;
 use OCP\IUserBackend;
 use OCP\Util;
 use Symfony\Component\EventDispatcher\EventDispatcher;
@@ -83,6 +85,7 @@ class Database extends Backend implements IUserBackend {
 
 	/**
 	 * Create a new user
+	 *
 	 * @param string $uid The username of the user to create
 	 * @param string $password The password of the new user
 	 * @return bool
@@ -112,6 +115,7 @@ class Database extends Backend implements IUserBackend {
 
 	/**
 	 * delete a user
+	 *
 	 * @param string $uid The username of the user to delete
 	 * @return bool
 	 *
@@ -131,6 +135,7 @@ class Database extends Backend implements IUserBackend {
 
 	/**
 	 * Set password
+	 *
 	 * @param string $uid The username
 	 * @param string $password The new password
 	 * @return bool
@@ -152,6 +157,7 @@ class Database extends Backend implements IUserBackend {
 
 	/**
 	 * Set display name
+	 *
 	 * @param string $uid The username
 	 * @param string $displayName The new display name
 	 * @return bool
@@ -172,6 +178,7 @@ class Database extends Backend implements IUserBackend {
 
 	/**
 	 * get display name of the user
+	 *
 	 * @param string $uid user ID of the user
 	 * @return string display name
 	 */
@@ -189,20 +196,29 @@ class Database extends Backend implements IUserBackend {
 	 * @return array an array of all displayNames (value) and the corresponding uids (key)
 	 */
 	public function getDisplayNames($search = '', $limit = null, $offset = null) {
-		$parameters = [];
-		$searchLike = '';
-		if ($search !== '') {
-			$parameters[] = '%' . \OC::$server->getDatabaseConnection()->escapeLikeParameter($search) . '%';
-			$parameters[] = '%' . \OC::$server->getDatabaseConnection()->escapeLikeParameter($search) . '%';
-			$searchLike = ' WHERE LOWER(`displayname`) LIKE LOWER(?) OR '
-				. 'LOWER(`uid`) LIKE LOWER(?)';
-		}
+		$connection = \OC::$server->getDatabaseConnection();
+
+		$query = $connection->getQueryBuilder();
+
+		$query->select('uid', 'displayname')
+			->from('users', 'u')
+			->leftJoin('u', 'preferences', 'p', $query->expr()->andX(
+				$query->expr()->eq('userid', 'uid')),
+				$query->expr()->eq('appid', new Literal('settings')),
+				$query->expr()->eq('configkey', new Literal('email'))
+			)
+			// sqlite doesn't like re-using a single named parameter here
+			->where($query->expr()->iLike('uid', $query->createPositionalParameter('%' . $connection->escapeLikeParameter($search) . '%')))
+			->orWhere($query->expr()->iLike('displayname', $query->createPositionalParameter('%' . $connection->escapeLikeParameter($search) . '%')))
+			->orWhere($query->expr()->iLike('configvalue', $query->createPositionalParameter('%' . $connection->escapeLikeParameter($search) . '%')))
+			->orderBy($query->func()->lower('displayname'), 'ASC')
+			->orderBy($query->func()->lower('uid'), 'ASC')
+			->setMaxResults($limit)
+			->setFirstResult($offset);
 
-		$displayNames = array();
-		$query = \OC_DB::prepare('SELECT `uid`, `displayname` FROM `*PREFIX*users`'
-			. $searchLike .' ORDER BY LOWER(`displayname`), LOWER(`uid`) ASC', $limit, $offset);
-		$result = $query->execute($parameters);
-		while ($row = $result->fetchRow()) {
+		$result = $query->execute();
+		$displayNames = [];
+		while ($row = $result->fetch()) {
 			$displayNames[$row['uid']] = $row['displayname'];
 		}
 
@@ -211,6 +227,7 @@ class Database extends Backend implements IUserBackend {
 
 	/**
 	 * Check if the password is correct
+	 *
 	 * @param string $uid The username
 	 * @param string $password The password
 	 * @return string
@@ -226,8 +243,8 @@ class Database extends Backend implements IUserBackend {
 		if ($row) {
 			$storedHash = $row['password'];
 			$newHash = '';
-			if(\OC::$server->getHasher()->verify($password, $storedHash, $newHash)) {
-				if(!empty($newHash)) {
+			if (\OC::$server->getHasher()->verify($password, $storedHash, $newHash)) {
+				if (!empty($newHash)) {
 					$this->setPassword($uid, $password);
 				}
 				return $row['uid'];
@@ -240,15 +257,16 @@ class Database extends Backend implements IUserBackend {
 
 	/**
 	 * Load an user in the cache
+	 *
 	 * @param string $uid the username
 	 * @return boolean true if user was found, false otherwise
 	 */
 	private function loadUser($uid) {
-		$uid = (string) $uid;
+		$uid = (string)$uid;
 		if (!isset($this->cache[$uid])) {
 			//guests $uid could be NULL or ''
 			if ($uid === '') {
-				$this->cache[$uid]=false;
+				$this->cache[$uid] = false;
 				return true;
 			}
 
@@ -285,26 +303,15 @@ class Database extends Backend implements IUserBackend {
 	 * @return string[] an array of all uids
 	 */
 	public function getUsers($search = '', $limit = null, $offset = null) {
-		$parameters = [];
-		$searchLike = '';
-		if ($search !== '') {
-			$parameters[] = '%' . \OC::$server->getDatabaseConnection()->escapeLikeParameter($search) . '%';
-			$searchLike = ' WHERE LOWER(`uid`) LIKE LOWER(?)';
-			$parameters[] = '%' . \OC::$server->getDatabaseConnection()->escapeLikeParameter($search) . '%';
-			$searchLike .= ' OR LOWER(`displayname`) LIKE LOWER(?)';
-		}
-
-		$query = \OC_DB::prepare('SELECT `uid` FROM `*PREFIX*users`' . $searchLike . ' ORDER BY LOWER(`uid`) ASC', $limit, $offset);
-		$result = $query->execute($parameters);
-		$users = array();
-		while ($row = $result->fetchRow()) {
-			$users[] = $row['uid'];
-		}
-		return $users;
+		$users = $this->getDisplayNames($search, $limit, $offset);
+		$userIds = array_keys($users);
+		sort($userIds, SORT_STRING | SORT_FLAG_CASE);
+		return $userIds;
 	}
 
 	/**
 	 * check if a user exists
+	 *
 	 * @param string $uid the username
 	 * @return boolean
 	 */
@@ -315,6 +322,7 @@ class Database extends Backend implements IUserBackend {
 
 	/**
 	 * get the user's home directory
+	 *
 	 * @param string $uid the username
 	 * @return string|false
 	 */
@@ -364,14 +372,15 @@ class Database extends Backend implements IUserBackend {
 
 	/**
 	 * Backend name to be shown in user management
+	 *
 	 * @return string the name of the backend to be shown
 	 */
-	public function getBackendName(){
+	public function getBackendName() {
 		return 'Database';
 	}
 
 	public static function preLoginNameUsedAsUserName($param) {
-		if(!isset($param['uid'])) {
+		if (!isset($param['uid'])) {
 			throw new \Exception('key uid is expected to be set in $param');
 		}
 
diff --git a/lib/public/DB/QueryBuilder/IFunctionBuilder.php b/lib/public/DB/QueryBuilder/IFunctionBuilder.php
index 478fd8794044cb607b3c5dfca409ca153f30963d..b82749d54254c2ff6dc6cd61fadb972218a098d5 100644
--- a/lib/public/DB/QueryBuilder/IFunctionBuilder.php
+++ b/lib/public/DB/QueryBuilder/IFunctionBuilder.php
@@ -71,4 +71,13 @@ interface IFunctionBuilder {
 	 * @since 12.0.0
 	 */
 	public function sum($field);
+
+	/**
+	 * Transforms a string field or value to lower case
+	 *
+	 * @param mixed $field
+	 * @return IQueryFunction
+	 * @since 13.0.0
+	 */
+	public function lower($field);
 }
diff --git a/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php b/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php
index ff58b3f6e0bfed3a92e9327598aec77d187eea77..1bf42d230fec3083f9aae4115b283bda6d9e1214 100644
--- a/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php
+++ b/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php
@@ -48,7 +48,9 @@ class ExpressionBuilderTest extends TestCase {
 
 		$this->connection = \OC::$server->getDatabaseConnection();
 
-		$this->expressionBuilder = new ExpressionBuilder($this->connection);
+		$queryBuilder = $this->createMock(IQueryBuilder::class);
+
+		$this->expressionBuilder = new ExpressionBuilder($this->connection, $queryBuilder);
 
 		$this->doctrineExpressionBuilder = new DoctrineExpressionBuilder($this->connection);
 	}
diff --git a/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php b/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php
index e89da0fbc92e4d9a3c526e6d771cd548e9236877..869faccc5ccc93feb88e975b4b5e8c50ec481fbc 100644
--- a/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php
+++ b/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php
@@ -79,4 +79,14 @@ class FunctionBuilderTest extends TestCase {
 
 		$this->assertEquals('oobar', $query->execute()->fetchColumn());
 	}
+
+	public function testLower() {
+		$query = $this->connection->getQueryBuilder();
+
+		$query->select($query->func()->lower($query->createNamedParameter('FooBar')));
+		$query->from('appconfig')
+			->setMaxResults(1);
+
+		$this->assertEquals('foobar', $query->execute()->fetchColumn());
+	}
 }
diff --git a/tests/lib/User/Backend.php b/tests/lib/User/Backend.php
index 85ccbac913c254e7334ece1cf71bb90f9d1b2d22..1c7d482c48089e9ae41fb95d54e1b16ba2416752 100644
--- a/tests/lib/User/Backend.php
+++ b/tests/lib/User/Backend.php
@@ -103,15 +103,23 @@ abstract class Backend extends \Test\TestCase {
 		$name1 = 'foobarbaz';
 		$name2 = 'bazbarfoo';
 		$name3 = 'notme';
+		$name4 = 'under_score';
 
 		$this->backend->createUser($name1, 'pass1');
 		$this->backend->createUser($name2, 'pass2');
 		$this->backend->createUser($name3, 'pass3');
+		$this->backend->createUser($name4, 'pass4');
 
 		$result = $this->backend->getUsers('bar');
-		$this->assertSame(2, count($result));
+		$this->assertCount(2, $result);
 
 		$result = $this->backend->getDisplayNames('bar');
-		$this->assertSame(2, count($result));
+		$this->assertCount(2, $result);
+
+		$result = $this->backend->getUsers('under_');
+		$this->assertCount(1, $result);
+
+		$result = $this->backend->getUsers('not_');
+		$this->assertCount(0, $result);
 	}
 }
diff --git a/tests/lib/User/DatabaseTest.php b/tests/lib/User/DatabaseTest.php
index 0e6900651cdd3684637047093f0c120c22287db3..a6fb8047a98a2a29457fa9ac3c17ff6b46df1bd3 100644
--- a/tests/lib/User/DatabaseTest.php
+++ b/tests/lib/User/DatabaseTest.php
@@ -24,6 +24,7 @@ namespace Test\User;
 use OC\HintException;
 use Symfony\Component\EventDispatcher\EventDispatcher;
 use Symfony\Component\EventDispatcher\GenericEvent;
+use OC\User\User;
 
 /**
  * Class DatabaseTest
@@ -113,4 +114,39 @@ class DatabaseTest extends Backend {
 		$this->backend->createUser($user1, 'pw2');
 		$this->assertTrue($this->backend->userExists($user1));
 	}
+
+	public function testSearch() {
+		parent::testSearch();
+
+		$user1 = $this->getUser();
+		$this->backend->createUser($user1, 'pass1');
+
+		$user2 = $this->getUser();
+		$this->backend->createUser($user2, 'pass1');
+
+		$user1Obj = new User($user1, $this->backend);
+		$user2Obj = new User($user2, $this->backend);
+		$emailAddr1 = "$user1@nextcloud.com";
+		$emailAddr2 = "$user2@nextcloud.com";
+
+		$user1Obj->setDisplayName('User 1 Display');
+
+		$result = $this->backend->getDisplayNames('display');
+		$this->assertCount(1, $result);
+
+		$result = $this->backend->getDisplayNames(strtoupper($user1));
+		$this->assertCount(1, $result);
+
+		$user1Obj->setEMailAddress($emailAddr1);
+		$user2Obj->setEMailAddress($emailAddr2);
+
+		$result = $this->backend->getUsers('@nextcloud.com');
+		$this->assertCount(2, $result);
+
+		$result = $this->backend->getDisplayNames('@nextcloud.com');
+		$this->assertCount(2, $result);
+
+		$result = $this->backend->getDisplayNames('@nextcloud.COM');
+		$this->assertCount(2, $result);
+	}
 }