diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/AuthorizationDataProvider.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/AuthorizationDataProvider.java
index e3ac6ef112f12704f6b09dfa92bab9cdd82d1a89..784f9ffb238bcc2a8ec85333b1d622f2e123c20f 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/AuthorizationDataProvider.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/AuthorizationDataProvider.java
@@ -1,5 +1,6 @@
 package ch.systemsx.cisd.openbis.generic.server.authorization;
 
+import java.sql.Connection;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -478,4 +479,10 @@ final public class AuthorizationDataProvider implements IAuthorizationDataProvid
     {
         return list;
     }
+
+    @Override
+    public Connection getConnection()
+    {
+        return daoFactory.getConnection();
+    }
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java
index 6e82eefebdf9ab9dda55e889e3e26bde3a595ba4..398a3e9e0a3bff0743ec6687cbeca35c45347cad 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java
@@ -16,6 +16,7 @@
 
 package ch.systemsx.cisd.openbis.generic.server.business.bo;
 
+import java.sql.Connection;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -442,4 +443,11 @@ abstract class AbstractBusinessObject implements IDAOFactory
     {
         return daoFactory.getExternalDataManagementSystemDAO();
     }
+
+    @Override
+    public Connection getConnection()
+    {
+        return daoFactory.getConnection();
+    }
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IAuthorizationDAOFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IAuthorizationDAOFactory.java
index 1cc915c0e30558f089dc47e1013e1278a8970f7a..49d1c3648ec90d2bb2145b740e8308d14de1e8e3 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IAuthorizationDAOFactory.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IAuthorizationDAOFactory.java
@@ -16,6 +16,8 @@
 
 package ch.systemsx.cisd.openbis.generic.server.dataaccess;
 
+import java.sql.Connection;
+
 import org.hibernate.SessionFactory;
 
 import ch.systemsx.cisd.openbis.generic.shared.dto.DatabaseInstancePE;
@@ -74,4 +76,9 @@ public interface IAuthorizationDAOFactory
     public IRelationshipTypeDAO getRelationshipTypeDAO();
 
     public IDeletionDAO getDeletionDAO();
+
+    /**
+     * Returns the JDBC connection.
+     */
+    public Connection getConnection();
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AuthorizationDAOFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AuthorizationDAOFactory.java
index 2b5e07946ac1d87a4ce10682d3dec43517935862..f3418946584f568293fd99e2ce5740013ff53b4b 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AuthorizationDAOFactory.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AuthorizationDAOFactory.java
@@ -16,6 +16,8 @@
 
 package ch.systemsx.cisd.openbis.generic.server.dataaccess.db;
 
+import java.sql.Connection;
+
 import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
 import org.hibernate.SessionFactory;
@@ -280,4 +282,12 @@ public class AuthorizationDAOFactory implements IAuthorizationDAOFactory
         HibernateUtils.setBatchUpdateMode(currentSession, batchMode);
     }
 
+    @SuppressWarnings("deprecation")
+    @Override
+    public Connection getConnection()
+    {
+        final SessionFactory sessionFactory = persistencyResources.getSessionFactoryOrNull();
+        return sessionFactory.getCurrentSession().connection();
+    }
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/IAuthorizationDataProvider.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/IAuthorizationDataProvider.java
index 405d82b12370e58288f5cf6c4b5aa95e26638691..5276e843d7842913b232e0cabeb336c1632d223d 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/IAuthorizationDataProvider.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/IAuthorizationDataProvider.java
@@ -16,6 +16,7 @@
 
 package ch.systemsx.cisd.openbis.generic.shared.authorization;
 
+import java.sql.Connection;
 import java.util.List;
 import java.util.Set;
 
@@ -148,4 +149,9 @@ public interface IAuthorizationDataProvider extends IDatabaseInstanceFinder
      * Fetches all deletions with given tech ids.
      */
     public List<DeletionPE> getDeletions(List<TechId> deletionIds);
+
+    /**
+     * Returns the JDBC connection.
+     */
+    public Connection getConnection();
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/AbstractSpacePredicate.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/AbstractSpacePredicate.java
index 0781299114560cdb4ccc163207092899e095f6c4..947924f1cf239f669127856c4b87d6aff6929bc1 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/AbstractSpacePredicate.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/AbstractSpacePredicate.java
@@ -76,7 +76,7 @@ public abstract class AbstractSpacePredicate<T> extends AbstractDatabaseInstance
                 return Status.OK;
             } else
             {
-                return createError(person, spaceCodeOrNull);
+                return createError(person);
             }
         }
 
@@ -85,13 +85,44 @@ public abstract class AbstractSpacePredicate<T> extends AbstractDatabaseInstance
         {
             return Status.OK;
         }
-        return createError(person, spaceCodeOrNull);
+        return createError(person);
     }
 
-    private Status createError(final PersonPE person, final String spaceCodeOrNull)
+    protected Status evaluate(final PersonPE person, final List<RoleWithIdentifier> allowedRoles,
+            final DatabaseInstancePE databaseInstance, final long spaceTechId)
+    {
+        final String databaseInstanceUUID = databaseInstance.getUuid();
+        return evaluate(person, allowedRoles, databaseInstanceUUID, databaseInstance.getCode(),
+                spaceTechId);
+    }
+
+    protected Status evaluate(final PersonPE person, final List<RoleWithIdentifier> allowedRoles,
+            final String databaseInstanceUUID, final String databaseInstanceCode,
+            final long spaceTechId)
+    {
+        if (tryFindSpace(databaseInstanceUUID, spaceTechId) == null)
+        {
+            if (okForNonExistentSpaces)
+            {
+                return Status.OK;
+            } else
+            {
+                return createError(person);
+            }
+        }
+
+        final boolean matching = isMatching(allowedRoles, databaseInstanceUUID, spaceTechId);
+        if (matching)
+        {
+            return Status.OK;
+        }
+        return createError(person);
+    }
+
+    private Status createError(final PersonPE person)
     {
         return Status.createError(String.format("User '%s' does not have enough privileges.",
-                person.getUserId(), spaceCodeOrNull));
+                person.getUserId()));
     }
 
     private SpacePE tryFindSpace(final String databaseInstanceUUID, final String spaceCode)
@@ -106,6 +137,18 @@ public abstract class AbstractSpacePredicate<T> extends AbstractDatabaseInstance
         return null;
     }
 
+    private SpacePE tryFindSpace(final String databaseInstanceUUID, final long spaceTechId)
+    {
+        for (final SpacePE space : spaces)
+        {
+            if (equalIdentifier(space, databaseInstanceUUID, spaceTechId))
+            {
+                return space;
+            }
+        }
+        return null;
+    }
+
     private boolean isMatching(final List<RoleWithIdentifier> allowedRoles,
             final String databaseInstanceUUID, final String spaceCodeOrNull)
     {
@@ -128,6 +171,28 @@ public abstract class AbstractSpacePredicate<T> extends AbstractDatabaseInstance
         return false;
     }
 
+    private boolean isMatching(final List<RoleWithIdentifier> allowedRoles,
+            final String databaseInstanceUUID, final long spaceTechId)
+    {
+        for (final RoleWithIdentifier role : allowedRoles)
+        {
+            final RoleLevel roleLevel = role.getRoleLevel();
+            if (roleLevel.equals(RoleLevel.SPACE)
+                    && equalIdentifier(role.getAssignedSpace(), databaseInstanceUUID,
+                            spaceTechId))
+            {
+                return true;
+            } else if (roleLevel.equals(RoleLevel.INSTANCE)
+                    && role.getAssignedDatabaseInstance().getUuid().equals(databaseInstanceUUID))
+            {
+                // permissions on the database instance level allow to access all spaces in this
+                // instance
+                return true;
+            }
+        }
+        return false;
+    }
+
     private boolean equalIdentifier(final SpacePE space, final String databaseInstanceUUID,
             final String spaceCodeOrNull)
     {
@@ -135,14 +200,22 @@ public abstract class AbstractSpacePredicate<T> extends AbstractDatabaseInstance
                 && space.getDatabaseInstance().getUuid().equals(databaseInstanceUUID);
     }
 
-    protected Status evaluateSpace(final PersonPE person, final List<RoleWithIdentifier> allowedRoles, final SpacePE spaceOrNull)
+    private boolean equalIdentifier(final SpacePE space, final String databaseInstanceUUID,
+            final long spaceTechId)
+    {
+        return (space.getId() == spaceTechId)
+                && space.getDatabaseInstance().getUuid().equals(databaseInstanceUUID);
+    }
+
+    protected Status evaluateSpace(final PersonPE person,
+            final List<RoleWithIdentifier> allowedRoles, final SpacePE spaceOrNull)
     {
         if (spaceOrNull == null)
         {
             return Status.createError(String.format("User '%s' does not have enough privileges.",
                     person.getUserId()));
         }
-    
+
         final String spaceCode = SpaceCodeHelper.getSpaceCode(person, spaceOrNull);
         final DatabaseInstancePE databaseInstance = spaceOrNull.getDatabaseInstance();
         return evaluate(person, allowedRoles, databaseInstance, spaceCode);
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/internal/authorization/ScreeningPlateListReadOnlyPredicate.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/internal/authorization/ScreeningPlateListReadOnlyPredicate.java
index d705b54cc97f509b7cf76385c7605de3677904d6..bd25d5432b538da29960d0e8b824a92f26a2b0b4 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/internal/authorization/ScreeningPlateListReadOnlyPredicate.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/internal/authorization/ScreeningPlateListReadOnlyPredicate.java
@@ -16,15 +16,22 @@
 
 package ch.systemsx.cisd.openbis.plugin.screening.shared.api.internal.authorization;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
+
+import net.lemnik.eodsql.BaseQuery;
+import net.lemnik.eodsql.QueryTool;
+import net.lemnik.eodsql.Select;
 
 import ch.systemsx.cisd.common.exceptions.Status;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.StringArrayMapper;
 import ch.systemsx.cisd.openbis.generic.shared.authorization.RoleWithIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.authorization.annotation.ShouldFlattenCollections;
 import ch.systemsx.cisd.openbis.generic.shared.authorization.predicate.AbstractSpacePredicate;
-import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
 import ch.systemsx.cisd.openbis.generic.shared.util.SpaceCodeHelper;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateIdentifier;
 
@@ -52,27 +59,16 @@ public class ScreeningPlateListReadOnlyPredicate extends
     protected Status doEvaluation(PersonPE person, List<RoleWithIdentifier> allowedRoles,
             List<? extends PlateIdentifier> plates)
     {
+        final List<String> permIds = new ArrayList<String>(plates.size());
         for (PlateIdentifier plate : plates)
         {
             if (plate.getPermId() != null)
             {
-                final SamplePE sampleOrNull =
-                        authorizationDataProvider.tryGetSampleByPermId(plate.getPermId());
-                if (sampleOrNull == null)
-                {
-                    return Status.createError(String.format(
-                            "User '%s' does not have enough privileges.", person.getUserId()));
-                }
-                final SpacePE space = sampleOrNull.getSpace();
-                final Status status =
-                        evaluate(person, allowedRoles, space.getDatabaseInstance(), space.getCode());
-                if (Status.OK.equals(status) == false)
-                {
-                    return status;
-                }
+                permIds.add(plate.getPermId());
             } else
             {
-                final String spaceCode = SpaceCodeHelper.getSpaceCode(person, plate.tryGetSpaceCode());
+                final String spaceCode =
+                        SpaceCodeHelper.getSpaceCode(person, plate.tryGetSpaceCode());
                 if (plate.isSharedPlate() == false)
                 {
                     final Status status =
@@ -85,7 +81,52 @@ public class ScreeningPlateListReadOnlyPredicate extends
                 }
             }
         }
+        if (permIds.isEmpty() == false)
+        {
+            for (Long spaceId : getSampleSpaceIds(permIds))
+            {
+                final Status status =
+                        evaluate(person, allowedRoles, authorizationDataProvider
+                                .getHomeDatabaseInstance(), spaceId);
+                if (Status.OK.equals(status) == false)
+                {
+                    return status;
+                }
+            }
+        }
         return Status.OK;
     }
 
+    private final static int SAMPLE_PERM_ID_LIMIT = 999;
+
+    interface ISampleToSpaceQuery extends BaseQuery
+    {
+        @Select(sql = "select distinct space_id from samples where perm_id = any(?{1})", parameterBindings =
+            { StringArrayMapper.class })
+        public List<Long> getSampleSpaceIds(String[] samplePermIds);
+    }
+
+    private Collection<Long> getSampleSpaceIds(final List<String> permIds)
+    {
+        final ISampleToSpaceQuery query =
+                QueryTool.getQuery(authorizationDataProvider.getConnection(),
+                        ISampleToSpaceQuery.class);
+        if (permIds.size() > SAMPLE_PERM_ID_LIMIT)
+        {
+            final Set<Long> spaceIds = new HashSet<Long>(permIds.size());
+            for (int startIdx = 0; startIdx < permIds.size(); startIdx += SAMPLE_PERM_ID_LIMIT)
+            {
+                final List<String> permIdSubList = permIds.subList(startIdx,
+                        Math.min(permIds.size(), startIdx + SAMPLE_PERM_ID_LIMIT));
+                spaceIds.addAll(query.getSampleSpaceIds(permIdSubList.toArray(
+                        new String[permIdSubList.size()])));
+            }
+            return spaceIds;
+        } else
+        {
+            return query
+                    .getSampleSpaceIds(permIds.toArray(new String[permIds.size()]));
+        }
+    }
+
 }