Download Latest Version v3.14.0 source code.zip (14.1 MB) Google Add to Preferred Sources
Home / v3.14.0
Name Modified Size InfoDownloads / Week
Parent folder
README.md 2026-10-16 23.9 kB
v3.14.0 source code.tar.gz 2026-10-16 10.1 MB
v3.14.0 source code.zip 2026-10-16 14.1 MB
Totals: 3 Items   24.3 MB 0

Memgraph v3.14.0 - October 21st, 2026

⚠️ Breaking changes

  • A user or tenant profile change inside an explicit transaction is refused. It previously applied immediately and was not undone by ROLLBACK. Run profile changes as a single query. #4524
  • SHOW TRANSACTIONS gains a database column with the database each transaction runs on (for snapshot and garbage collection rows, the database being processed). SHOW ACTIVE USERS INFO gains database and database marked for deletion. Clients that parse these results by column position need to account for the new fields. #4571
  • Edge index operator metrics are merged into memgraph_scan_all_by_edge_type_property_operator_total and memgraph_scan_all_by_edge_property_operator_total. Dashboards that scrape the older _value or _range series need those names updated. #4671
  • Comparing an edge property with a type it cannot match, such as a boolean or a point, now returns no rows instead of raising. Update queries that relied on that error. #4671
  • A pattern that names an already-bound variable is now a node test, including in plain MATCH. After OPTIONAL MATCH, MATCH (b) no longer keeps a null b row; it drops it (or errors if b is not a node). In EXISTS / COUNT / COLLECT, a pattern may also no longer reuse a name from outside the body. Rename those variables, or drop a no-op MATCH on a bound name. #4707
  • Functions in the collections query module (contains, to_set, union and duplicates) now treat maps with the same keys and values as equal, matching Cypher's =. Queries that relied on every non-empty map being distinct will see different results. Custom C++ query modules need to be recompiled for this release. #4783
  • Comparing lists or maps that hold null now returns null, the same as null = null, instead of treating them as equal. Update filters and conditions that assumed [null] = [null] or {a: null} = {a: null} was true. DISTINCT and grouping still treat those values as the same key. #4794
  • NaN > x and NaN >= x now return false instead of true. A filter on those operators keeps no row where it previously kept every row. #4816
  • Comparing values with <, <=, > or >= no longer fails the query when the pair has no order. Two booleans are ordered as Cypher orders them (false < true). A pair such as two points or two lists returns null. #4816
  • An indexed range over a date, local time, local date time or duration returns only values of that same kind. It previously also returned the other three. Recheck range queries on mixed temporal properties. #4816
  • A uniqueness constraint now allows two nodes whose property holds null at any depth, such as [1, null] or {a: null}. It previously refused the second. Recheck constraints that relied on that refusal. #4836

✨ New features

  • Auth queries such as CREATE USER, GRANT and SET PASSWORD can run in an explicit transaction and apply together or not at all. A transaction cannot mix auth and data queries. SHOW TRANSACTIONS shows passwords as '****'. #4524
  • DROP DATABASE ... FORCE returns immediately and the database is torn down in the background. Until that finishes, SHOW DATABASES lists it as DROPPING with health draining, for up to about 10 seconds even when nothing uses it. If the same name is created again meanwhile, the draining row is shown as name (uuid). Dropping a name that is still draining fails with Database <name> is currently being dropped. #4573
  • SHOW SESSIONS lists active Bolt sessions (session_id, username, database, login_timestamp). TERMINATE SESSIONS evicts sessions by uuid from another connection. A user may manage their own sessions; terminating another user's session requires TRANSACTION_MANAGEMENT on that session's database. #4577
  • The collections query module adds index_of(coll, value): the position of the first element equal to value, or -1. A null collection or value returns null. #4783
  • The built-in nullIf(value1, value2) returns null when the two arguments are equal, and the first argument otherwise — the counterpart of coalesce. The comparison is the same as =, so nullIf(1, null) returns 1. #4786
  • OPTIONAL CALL keeps an input row when the subquery body returns nothing for it, and sets the body's returned columns to null. Without OPTIONAL, that row is dropped. Supported with a scope clause, (*), no scope, UNION, nesting, and IN TRANSACTIONS. #4833
  • After DROP DATABASE ... FORCE, Memgraph closes the Bolt sessions still using that database within about 10 seconds, so the drop can finish. Clients see a disconnect and can reconnect. #4843
  • Aggregation functions can be used inside a CASE expression in RETURN and WITH. They were previously refused. Aggregations in ORDER BY are still refused. #4859
  • Node patterns and expressions accept label expressions built with &, |, !, % and parentheses, for example MATCH (n:Person&Employee) or WHERE n:A|B. % means the node has at least one label. CREATE and MERGE accept only & and parentheses. SET and REMOVE still take labels as :Label only. #4877
  • The FIPS Docker image now includes a Python interpreter, so Python query modules and auth modules run on that image. #4902
  • An EXISTS { ... }, COUNT { ... } or COLLECT { ... } body can contain UNWIND, for example COUNT { UNWIND n.list AS x RETURN x }. Write clauses stay refused in these bodies. #4915
  • ORDER BY, and a WITH's WHERE, can repeat an expression that an aggregating RETURN or WITH projects, for example RETURN n.type, count(n.value) ORDER BY count(n.value) DESC. #4951
  • SHOW STORAGE INFO now reports disk_available, the free space on the filesystem that holds the data directory. #4952
  • A CALL subquery can choose which body to run per input row with WHEN … THEN … branches and an optional ELSE, for example CALL (n) { WHEN n.ok THEN CREATE (:A) ELSE CREATE (:B) }. #4984

🐞 Bug fixes

  • After a data instance joins a high-availability cluster, OpenMetrics scrapes now use the cluster UUID for the default database on every instance. Series for database="memgraph" can be aggregated across the cluster. #4275
  • AFTER COMMIT triggers no longer run for transactions that fail to commit (for example a STRICT_SYNC write that aborts). They fire only when the commit succeeds. On shutdown or DROP TRIGGER, any queued trigger work that cannot run is logged instead of being discarded silently. #4565
  • During a license refresh, a query could briefly skip Enterprise permission checks. Those checks stay enforced while the license is revalidated. #4566
  • Dropping a database while a write is still committing no longer crashes a replica registered with STRICT_SYNC. The in-flight commit is aborted before the database is removed. #4568
  • Switching a database to on-disk storage mode is less likely to fail because of brief concurrent activity (for example a metrics scrape or a Lab connection between queries). Those no longer block the switch immediately. If another session still holds the database after a short wait, the switch fails as before, because exclusive access is required. #4569
  • Dropping or renaming a multi-tenant database with a tenant profile now persists correctly, including across crashes and replication. #4570
  • DROP DATABASE no longer hangs when an index is being built or TTL is running in the background. #4572
  • Dropping an index is safe to roll back and to replay after recovery, including when drops run alongside other writers or each other. #4741
  • Bolt stays usable when a query fails after streaming a large result. #4758
  • Dropping a database now also drops that database's server-side parameters (SET PARAMETER), including across replication and recovery. They no longer linger and reappear on replicas. #4774
  • Creating or resuming a database at the memory limit no longer fails while setting up stream support. #4785
  • A procedure inside CALL { ... }, and clauses below it in that subquery, now run for every input row instead of only the first. Affected queries return different results and can write different data, including CALL { ... } IN TRANSACTIONS. #4832
  • A property holding NaN is kept in an index and found again. An IS NOT NULL count on that property no longer shrinks or changes from run to run once the index exists. #4836
  • DISTINCT and grouping treat two NaNs as one value. A point with a NaN coordinate is handled the same way. = is unchanged and still returns false for a NaN. #4846
  • ORDER BY places a NaN after every number, including positive infinity, and two NaNs sort together. A column that held a NaN no longer has an arbitrary order. #4849
  • ORDER BY sorts a column that holds more than one type, placing each row by its type (map, node, relationship, list, path, string, boolean, number, then null). A pair of the same type with no order of its own, such as two maps, is still refused. #4852
  • An integer and a double are compared by the value each holds, so a large integer is no longer treated as equal to the nearest double that cannot represent it. =, ordering, ORDER BY, DISTINCT, indexes and unique constraints agree on such pairs. 1 = 1.0 is unchanged. #4854
  • List properties keep large integers as written (for example 2147483648 no longer comes back as a different number), and range filters on list properties return the matching rows. #4865
  • An index holds property values in the same order as ORDER BY, so a query over a column with more than one type returns the same rows in the same order with or without an index. Two date-time values at the same instant in different time zones are ordered by offset before zone name. #4880
  • MIN and MAX work on a column that holds more than one type, and return the first and last values in ORDER BY order. A NaN counts as the largest number. #4882
  • DISTINCT and grouping tell apart doubles that fall between the same pair of integers (for example 2.25 and 2.5). A whole double still matches the integer it equals. #4891
  • Hash lookups find a list of numbers, a point that holds a NaN, and a vector index identifier again when the value is stored in a different form or the NaN bits differ. #4895
  • A node with more than one unique constraint no longer leaks memory when a write touches only one of them, including under USING PERIODIC COMMIT and CALL { ... } IN TRANSACTIONS. #4848
  • EXISTS { ... }, COUNT { ... } and COLLECT { ... } in a WHERE no longer fail or keep the wrong rows when the body reads the outer query only through a WHERE, a WITH, a later UNION branch, or a nested subquery. WHERE n.prop = COUNT { ... } also returns the same rows with a label-property index as without one. #4874
  • Concurrent edge writes no longer crash during garbage collection. #4878
  • SHOW REPLICATION LAG now reports the correct lag for STRICT_SYNC replicas. #4884
  • STARTS WITH on an indexed property no longer returns nothing when the prefix is made entirely of 0xFF bytes. #4886
  • Creating or dropping a database no longer makes a healthy MAIN look down to the coordinator. Cluster health checks are answered while that operation holds its lock, so MAIN is not demoted. #4903
  • SHOW INSTANCE now works on a coordinator that is still joining the cluster. #4911
  • Switching users on a pooled Bolt connection now clears the previous user's session state: SET SESSION and pending SET NEXT isolation levels, SET SESSION SETTING values, SET SESSION TRACE and the database selected with USE DATABASE. The new session's requested impersonated user is applied and checked against the new user's privileges. #4932
  • Setting a property to the value it already holds no longer fires an ON UPDATE trigger when that value is a NaN, or a list or map that holds a null. #4936
  • Label disjunctions now return the correct rows, including two :A|B tests on the same node and WHERE n:A OR m:B. #4948
  • Vertex vector indexes recover correctly after a crash or snapshot load. An empty list [] on a vector-indexed property stays []. #4953
  • valueType() now returns VIRTUAL_GRAPH for the graph that derive() returns. #4954
  • Comparing two lists with <, <=, > or >= now uses dictionary order instead of raising. #4956
  • Edge vector indexes recover correctly after a crash or snapshot load. #4959
  • On a coordinator without SSO, login now succeeds with a Bolt scheme that is not listed in --auth-module-mappings. #4962
  • REMOVE COORDINATOR now finishes if the same query is retried after a timeout, instead of failing with "no such id". #4968
  • After DROP DATABASE ... FORCE, a Bolt connection that was on that database is now closed, so the driver reconnects instead of staying stuck on "Database required". #4969
  • Periodic snapshots on a replica record the correct epoch even when a new MAIN's first commit arrives while the snapshot is being written. #4982
  • CALL subqueries with a UNION or UNION ALL body return the outer rows, make writes in or before the CALL visible to later clauses, and expose the body's columns to RETURN *, WITH * and CALL (*). #4983
  • Rolling back a map-style property write (SET n = {...}, SET n = {}, SET n += {...}, and the same on edges) keeps a vector-indexed embedding and its index entry. #4991
  • A failed CREATE VECTOR INDEX or CREATE VECTOR EDGE INDEX (for example a dimension mismatch) leaves every node and edge property unchanged and readable. #4995
  • memgraph_show_instances_total counts only SHOW INSTANCES queries. OpenMetrics scrapes no longer increment it. #5005
  • After RENAME DATABASE, metrics scrapes report the new database name without a restart. #5006
  • Memory from abandoned commits is reclaimed again, instead of growing until restart. #5017
  • Signed numbers inside map or list values of system queries, such as SET GLOBAL PARAMETER p = {a: -1} or a vector index config, keep their value. Unsupported expressions there, such as {a: 1+1}, fail with a clear error. #5026
  • A session whose user, or every one of whose roles, was dropped is denied all privileges until it reconnects, even if a user with the same name is created again. Losing only some roles still removes just those roles' privileges. #5029
  • After RENAME DATABASE, TTL keeps deleting expired data on the renamed database, and index builds that run in the background finish. #5032
  • When an edge delete fails part-way and rolls back, the graph no longer keeps duplicate edges. Traversals do not over-count them, and replicas can apply the WAL without a full snapshot catch-up. #5105
  • An instance keeps running when the disk fills up while it writes a snapshot or receives files from main. CREATE SNAPSHOT returns a "not enough disk space" error. #5107
  • CREATE TRIGGER refuses a statement that is not a Cypher query, such as CREATE USER or CREATE INDEX. A trigger of that kind stored by an earlier version is skipped with a warning at startup. #5108
  • Vertices can be written to as usual after an edge creation on them fails. #5111
  • Snapshots created with multiple threads complete reliably. #5126
  • When Memgraph runs out of file descriptors, the Bolt, HTTP metrics and WebSocket listeners wait and retry, logging the error at most once every 10 seconds, and accept connections again once descriptors are available. #5129
  • The Memgraph systemd service sets LimitNOFILE=1048576, and Memgraph raises its soft open files limit to the hard limit at startup. A warning is logged when the limit stays below 65536. Deployments that kept the default soft limit of 1024 no longer hit Too many open files at around 950 connections. #5132
  • A pooled Bolt connection whose database was renamed or dropped gets an "unknown database" client error instead of running its queries on another database. A refused database or impersonation switch leaves the session unchanged. #5135
  • A query with an IN [...] list that hits a memory limit fails with "Memory limit exceeded", and the instance keeps running. #5139
  • During a rolling upgrade, a replica on an earlier version keeps users and roles intact. Users, roles, databases and parameters replicate to it again once it is upgraded, and until then SHOW REPLICAS shows it as invalid. #5156

🛠️ Improvements

  • Queries that set a timeout do less bookkeeping while they run, because the limit is checked against a shared clock instead of a per-query timer. #4662
  • With --experimental-enabled=commit-lock-narrowing, a new transaction can begin while a slow commit is still writing to the WAL or syncing to replicas, and reads the last fully committed state instead of waiting. The flag is off by default and can only be set at startup. #4685
  • Edge property indexes now answer STARTS WITH from the index alone. CONTAINS, ENDS WITH and regex read only the string run of the index, not every value of the property. #4671
  • Replicas apply incoming writes about twice as fast. #4714
  • KSHORTEST path expansion is much faster and uses less memory, especially for larger k, and equality and ordering comparisons between values are faster. #4733 #4760
  • Commits skip uniqueness and existence constraint checks for writes that cannot affect any constraint, so concurrent writers wait less on validation. #4769
  • Building Memgraph from source can reuse the compiler cache across different checkout paths of the same repository. #4795
  • A pattern comprehension that filters on a value from the outer query can use an index, for example MATCH (m:Item) RETURN [ (n:Item {id: m.id})--(q) | q ]. #4819
  • CONTAINS, ENDS WITH and regex on an indexed string under USING PARALLEL EXECUTION no longer scan the whole index column. #4827
  • path.expand_config uses less time and memory on a breadth-first walk with uniqueness: NODE_PATH or RELATIONSHIP_PATH when many paths reach the same node. Walks that never revisit a node can be slower. A memory-limit error now reports how many partial paths were held and suggests a hop bound or uniqueness: NODE_GLOBAL. #4875
  • DISTINCT and grouping over lists or maps that hold a null run about twice as fast. Results are unchanged. #4892
  • CONTAINS, ENDS WITH and regex on an indexed edge property are tested while reading the index, so non-matching values are dropped there rather than by a later filter. #4900
  • Cypher queries now parse faster the first time they run, especially relationships with a property map and exists() patterns. #4963
  • A slow login (SSO, auth module, or password) no longer blocks queries on other sessions. Permission checks during queries also wait less on the auth lock. #4966
  • Queries that evaluate expressions, including filters, run faster. #5014
Source: README.md, updated 2026-10-16