diff --git a/config/config.sample.php b/config/config.sample.php
index 18ac59f6cc9e39986222a208824005930d6bb39f..6005352e9d5d4baa6ff76658c6d15acd6918054f 100644
--- a/config/config.sample.php
+++ b/config/config.sample.php
@@ -1193,6 +1193,15 @@ $CONFIG = array(
  */
 'filelocking.enabled' => true,
 
+/**
+ * Set the time-to-live for locks in secconds.
+ *
+ * Any lock older than this will be automatically cleaned up.
+ *
+ * If not set this defaults to either 1 hour or the php max_execution_time, whichever is higher.
+ */
+'filelocking.ttl' => 3600,
+
 /**
  * Memory caching backend for file locking
  *
diff --git a/lib/private/Server.php b/lib/private/Server.php
index 581a2b44cead8b94d2787118cbdfe0da14916262..2ce895c6f725571d40a90d2c49611c0f044c6779 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -519,14 +519,17 @@ class Server extends ServerContainer implements IServerContainer {
 			);
 		});
 		$this->registerService('LockingProvider', function (Server $c) {
-			if ($c->getConfig()->getSystemValue('filelocking.enabled', true) or (defined('PHPUNIT_RUN') && PHPUNIT_RUN)) {
+			$ini = $c->getIniWrapper();
+			$config = $c->getConfig();
+			$ttl = $config->getSystemValue('filelocking.ttl', max(3600, $ini->getNumeric('max_execution_time')));
+			if ($config->getSystemValue('filelocking.enabled', true) or (defined('PHPUNIT_RUN') && PHPUNIT_RUN)) {
 				/** @var \OC\Memcache\Factory $memcacheFactory */
 				$memcacheFactory = $c->getMemCacheFactory();
 				$memcache = $memcacheFactory->createLocking('lock');
 				if (!($memcache instanceof \OC\Memcache\NullCache)) {
-					return new MemcacheLockingProvider($memcache);
+					return new MemcacheLockingProvider($memcache, $ttl);
 				}
-				return new DBLockingProvider($c->getDatabaseConnection(), $c->getLogger(), new TimeFactory());
+				return new DBLockingProvider($c->getDatabaseConnection(), $c->getLogger(), new TimeFactory(), $ttl);
 			}
 			return new NoopLockingProvider();
 		});
diff --git a/lib/private/lock/abstractlockingprovider.php b/lib/private/lock/abstractlockingprovider.php
index 7dee8c709a0af3a51a09aff6005bfd1e37b55a54..f96358778c1ba3b9f3eeea4ccde7b01e00e6e5f8 100644
--- a/lib/private/lock/abstractlockingprovider.php
+++ b/lib/private/lock/abstractlockingprovider.php
@@ -28,7 +28,7 @@ use OCP\Lock\ILockingProvider;
  * to release any left over locks at the end of the request
  */
 abstract class AbstractLockingProvider implements ILockingProvider {
-	const TTL = 3600; // how long until we clear stray locks in seconds
+	protected $ttl; // how long until we clear stray locks in seconds
 
 	protected $acquiredLocks = [
 		'shared' => [],
diff --git a/lib/private/lock/dblockingprovider.php b/lib/private/lock/dblockingprovider.php
index c10cd8636ad1b46c4deafda8a3d6c855e96c14c8..9e97df44d3f165f7fe02972c1cb03bfe15020000 100644
--- a/lib/private/lock/dblockingprovider.php
+++ b/lib/private/lock/dblockingprovider.php
@@ -93,11 +93,13 @@ class DBLockingProvider extends AbstractLockingProvider {
 	 * @param \OCP\IDBConnection $connection
 	 * @param \OCP\ILogger $logger
 	 * @param \OCP\AppFramework\Utility\ITimeFactory $timeFactory
+	 * @param int $ttl
 	 */
-	public function __construct(IDBConnection $connection, ILogger $logger, ITimeFactory $timeFactory) {
+	public function __construct(IDBConnection $connection, ILogger $logger, ITimeFactory $timeFactory, $ttl = 3600) {
 		$this->connection = $connection;
 		$this->logger = $logger;
 		$this->timeFactory = $timeFactory;
+		$this->ttl = $ttl;
 	}
 
 	/**
@@ -117,7 +119,7 @@ class DBLockingProvider extends AbstractLockingProvider {
 	 * @return int
 	 */
 	protected function getExpireTime() {
-		return $this->timeFactory->getTime() + self::TTL;
+		return $this->timeFactory->getTime() + $this->ttl;
 	}
 
 	/**
diff --git a/lib/private/lock/memcachelockingprovider.php b/lib/private/lock/memcachelockingprovider.php
index 08c92950e49bce93fbf581045af973eb4e7a1696..536b29e2c286f4ab2f1b0cad37dbb9f6dfcc3073 100644
--- a/lib/private/lock/memcachelockingprovider.php
+++ b/lib/private/lock/memcachelockingprovider.php
@@ -33,14 +33,16 @@ class MemcacheLockingProvider extends AbstractLockingProvider {
 
 	/**
 	 * @param \OCP\IMemcache $memcache
+	 * @param int $ttl
 	 */
-	public function __construct(IMemcache $memcache) {
+	public function __construct(IMemcache $memcache, $ttl = 3600) {
 		$this->memcache = $memcache;
+		$this->ttl = $ttl;
 	}
 
 	private function setTTL($path) {
 		if ($this->memcache instanceof IMemcacheTTL) {
-			$this->memcache->setTTL($path, self::TTL);
+			$this->memcache->setTTL($path, $this->ttl);
 		}
 	}
 
diff --git a/tests/lib/lock/dblockingprovider.php b/tests/lib/lock/dblockingprovider.php
index 2032110f4f099891fbbe80d5d746a8a3f0e2a462..743dbf85613bde238c51db2109b777945b72fe88 100644
--- a/tests/lib/lock/dblockingprovider.php
+++ b/tests/lib/lock/dblockingprovider.php
@@ -64,7 +64,7 @@ class DBLockingProvider extends LockingProvider {
 	 */
 	protected function getInstance() {
 		$this->connection = \OC::$server->getDatabaseConnection();
-		return new \OC\Lock\DBLockingProvider($this->connection, \OC::$server->getLogger(), $this->timeFactory);
+		return new \OC\Lock\DBLockingProvider($this->connection, \OC::$server->getLogger(), $this->timeFactory, 3600);
 	}
 
 	public function tearDown() {
@@ -81,7 +81,7 @@ class DBLockingProvider extends LockingProvider {
 		$this->instance->acquireLock('bar', ILockingProvider::LOCK_EXCLUSIVE);
 		$this->instance->changeLock('asd', ILockingProvider::LOCK_SHARED);
 
-		$this->currentTime = 150 + \OC\Lock\DBLockingProvider::TTL;
+		$this->currentTime = 150 + 3600;
 
 		$this->assertEquals(3, $this->getLockEntryCount());