Property-based access controlAuraDB Business CriticalAuraDB Virtual Dedicated CloudEnterprise Edition
Property-based access control grants or denies permission to read or traverse nodes or relationships based on property/value conditions. Each property-based privilege can only be restricted by a single property. For information about the syntax of these privileges, see Read privileges.
|
When using property-based access control, ensure the property used for the rule cannot be modified. Users who can change this property can affect the granted property-based privileges. |
|
Exercise caution when using |
Sharded property databases do not support property-based access control.
Syntax
To specify the property/value conditions of the privilege, you can use the following syntax:
{GRANT | DENY | REVOKE [GRANT | DENY]}
[IMMUTABLE]
{MATCH | READ | TRAVERSE}
ON { HOME GRAPH | GRAPH[S] { * | name[, ...] } }
[
ELEMENT[S] { * | label-or-rel-type[, ...] }
| NODE[S] { * | label[, ...] }
| RELATIONSHIP[S] { * | rel-type[, ...] }
| FOR {
([var][:label["|" ...]] "{" property: value "}")
| (var[:label["|" ...]])
WHERE [NOT] { var.property { = | <> | > | >= | < | <= } value | value { = | <> | > | >= | < | <= } var.property | var.property { IS NULL | IS NOT NULL } | var.property IN { "["[value[, ...]]"]" | listParam } | value IN var.property }
| (var[:label["|" ...]]
WHERE [NOT] { var.property { = | <> | > | >= | < | <= } value | value { = | <> | > | >= | < | <= } var.property | var.property { IS NULL | IS NOT NULL } | var.property IN { "["[value[, ...]]"]" | listParam } | value IN var.property } )
| ()[<]-"["[var][:type["|" ...]] "{" property: value "}" "]"-[>]()
| ()[<]-"["var[:type["|" ...]]"]"-[>]()
WHERE [NOT] { var.property { = | <> | > | >= | < | <= } value | value { = | <> | > | >= | < | <= } var.property | var.property { IS NULL | IS NOT NULL } | var.property IN { "["[value[, ...]]"]" | listParam } | value IN var.property }
| ()[<]-"["var[:type["|" ...]]
WHERE [NOT] { var.property { = | <> | > | >= | < | <= } value | value { = | <> | > | >= | < | <= } var.property | var.property { IS NULL | IS NOT NULL } | var.property IN { "["[value[, ...]]"]" | listParam } | value IN var.property } "]"-[>]()
}
]
{TO | FROM} role[, ...]
|
The following forms are available from Cypher 25 (introduced in Neo4j 2026.08):
In Cypher 5, the property must appear on the left-hand side of a scalar comparison operator, and |
Performance considerations
Adding property-based access control may lead to a significant performance overhead in certain scenarios. See Limitations for more detailed information.
When having property rules, the following factors can worsen the impact on performance:
-
The number of properties on the nodes and relationships concerned (more properties = greater performance impact).
-
The number of property-based privileges (more property-based privileges = greater performance impact).
-
The type of the privilege:
TRAVERSEproperty-based privileges have greater performance impact thanREADproperty-based privileges. -
The type of storage medium in operation. The impact of the property-based privileges on performance is considerably amplified by accessing disc storage.
To reduce the performance impact, it is recommended to use the block storage format as it is better optimized for the kind of read required for the resolution of property-based privileges.
For performance-critical scenarios, it is recommended to design privileges based on labels.
Examples
You can use the following syntax for defining a property-based privilege:
GRANT privilege-name ON GRAPH graph-name FOR pattern TO role-name
|
The user role does not need to have |
Grant a property-based privilege on a specific property using the value of another property
The following example shows how to grant permission to READ the address property on Email or Website nodes with domain exampledomain.com to role regularUsers:
GRANT READ { address } ON GRAPH * FOR (n:Email|Website) WHERE n.domain = 'exampledomain.com' TO regularUsers
Alternatively, you can use the following syntax:
GRANT READ { address } ON GRAPH * FOR (:Email|Website {domain: 'exampledomain.com'}) TO regularUsers
The following example shows how to grant permission to READ the since property on OWNS relationships having classification equal to UNCLASSIFIED to role regularUsers:
GRANT READ { since } ON GRAPH * FOR ()-[o:OWNS]-() WHERE o.classification = 'UNCLASSIFIED' TO regularUsers
Grant a property-based privilege with the property on either side of the operatorCypher 25Introduced in 2026.08
The property can appear on either side of a scalar comparison operator (=, <>, >, >=, <, ⇐).
The following example shows how to grant permission to READ all properties on nodes where the value 3 is less than the securityLevel property to the role regularUsers:
GRANT READ {*} ON GRAPH * FOR (n) WHERE 3 < n.securityLevel TO regularUsers
Placing the property on the right is equivalent to the property-on-the-left form n.securityLevel > 3.
When the property is on the right, the operator is mirrored, so this rule matches nodes whose securityLevel is greater than 3.
Regardless of the orientation used to create the privilege, it is always stored and listed in the canonical property-on-the-left form.
Running SHOW PRIVILEGES AS COMMANDS for the example above returns the rule as n.securityLevel > 3.
Grant a property-based privilege using NULL
The following example shows how to grant permission to TRAVERSE nodes with the label Email where property classification is NULL to role regularUsers:
GRANT TRAVERSE ON GRAPH * FOR (n:Email) WHERE n.classification IS NULL TO regularUsers
Deny a property-based privilege using a comparison operator
The following example shows how to deny permission to READ and TRAVERSE nodes and relationships where the property classification is different from UNCLASSIFIED to role regularUsers:
DENY MATCH {*} ON GRAPH * FOR (n) WHERE n.classification <> 'UNCLASSIFIED' TO regularUsers
DENY MATCH {*} ON GRAPH * FOR ()-[r]-() WHERE r.classification <> 'UNCLASSIFIED' TO regularUsers
|
These |
Grant a property-based privilege on all properties using a property value
The following example shows how to grant permission to READ all properties on nodes and relationships where the property securityLevel is higher than 3 to role regularUsers:
GRANT READ {*} ON GRAPH * FOR (n) WHERE n.securityLevel > 3 TO regularUsers
GRANT READ {*} ON GRAPH * FOR ()-[r]-() WHERE r.securityLevel > 3 TO regularUsers
|
The role |
Grant a property-based privilege using a list of values
The following example shows how to grant permission to READ all properties on nodes and relationships where the property classification is included in the list [UNCLASSIFIED, PUBLIC]:
GRANT READ {*} ON GRAPH * FOR (n) WHERE n.classification IN ['UNCLASSIFIED', 'PUBLIC'] TO regularUsers
GRANT READ {*} ON GRAPH * FOR ()-[r]-() WHERE r.classification IN ['UNCLASSIFIED', 'PUBLIC'] TO regularUsers
Grant a property-based privilege based on a value in a list propertyCypher 25Introduced in 2026.08
You can check whether a value is a member of a list-valued property using the value IN var.property syntax.
Here, the property stored on the node or relationship is a list, and the rule matches when the given value is an element of that list.
This is different from var.property IN [value, …], which checks whether a single-valued property matches one of the values in a given list.
The following example shows how to grant permission to READ all properties on nodes where the list-valued regions property contains the value 'EU' to the role regularUsers:
GRANT READ {*} ON GRAPH * FOR (n) WHERE 'EU' IN n.regions TO regularUsers
|
The value on the left of |
You can also negate the condition to match nodes and relationships whose list property does not contain the value.
The following example shows how to grant permission to READ and TRAVERSE nodes and relationships where the regions property does not contain the value 'EU' to the role regularUsers:
GRANT MATCH {*} ON GRAPH * FOR (n) WHERE NOT 'EU' IN n.regions TO regularUsers
GRANT MATCH {*} ON GRAPH * FOR ()-[r]-() WHERE NOT 'EU' IN r.regions TO regularUsers
|
The value on the left of |
Grant a property-based privilege using temporal value
The following example shows how to grant permission to READ all properties on nodes and relationships where the property createdAt is later than the current date:
GRANT READ {*} ON GRAPH * FOR (n) WHERE n.createdAt > date() TO regularUsers
GRANT READ {*} ON GRAPH * FOR ()-[r]-() WHERE r.createdAt > date() TO regularUsers
|
The |
|
Not all temporal values are comparable, see Cypher Manual → Equality, ordering, and comparison of value types. |
You can show the privilege created by the command in the previous example as a revoke command by running:
SHOW ROLE regularUsers PRIVILEGES AS REVOKE COMMANDS
| command |
|---|
Rows: 2 |