After 15 years on Business Central and NAV (and 30 in ERP overall) in factories across Greece, UK and the rest of Europe, I’ll tell you something most consultants still don’t understand properly: locking and blocking are usually not a SQL Server problem. They are application design problems.
Here is the part many people don’t want to hear: Business Central’s locking model is actually pretty solid. In most cases the real problem is not Microsoft. It is custom AL code, sloppy integrations, or long transactions that should never have been written as one big piece.
I’ve seen the same story many times, especially in Greek companies. The customer calls and says “the system is slow again.” Everyone blames BC. Three hours later we find a custom posting routine holding thousands of row locks while it waits for a vendor API to answer. Usually the fix is only four or five lines of better code.
The funny thing is Microsoft actually improved concurrency a lot in recent versions, specially v27. The platform is better than many people think, but bad AL code can still destroy performance very quickly.
Locking vs Blocking

Quick refresher because people mix these up constantly:
- Locking = normal behaviour. SQL protecting data consistency.
- Blocking = the real pain. One session waiting because something is already locked.
- Deadlock = the nightmare. Two sessions waiting for each other and SQL kills one process.
Business Central mostly uses row-level locking, which is good. But if your code touches too many records at once, SQL escalates to page or table locks. That’s when users start screaming and the whole factory feels frozen.
What’s New in v27 That Really Helps
Microsoft made some very useful improvements:
- Tri-state locking is now the default (optimistic concurrency).
- Record.ReadIsolation lets you lock only the exact record you need.
- Better telemetry and parallel posting options.
- Better handling for background sessions.
Practical advice from the field: If you are still using LockTable() everywhere like in the old NAV days, please stop. It destroys all the new optimistic behaviour for no reason.
My Favourite Feature in v27: The Database Locks Page
Just press Alt+Q and type “Database Locks”. You immediately see who is holding locks and who is waiting.
Before v27, when a customer in Greece called me saying the system was frozen, I had to ask IT for SQL Server Management Studio access. Now any administrator can check it directly inside BC.
One important thing people miss: it’s only a snapshot, not real-time monitoring. You need to refresh it during active blocking issues. But together with telemetry it helps you find the guilty object very quickly.
The AL Patterns That Matter Most
After all these years, these are the habits that prevent 80% of the blocking problems I see.
1. Keep write transactions short
The single biggest mistake I see: one giant transaction processing thousands of records.
Bad way (one big transaction):
if Item.FindSet() then
repeat
Item."Last Updated" := Today;
Item.Modify();
until Item.Next() = 0;
Commit; // only at the end
Better way:
Counter := 0;
if Item.FindSet() then
repeat
Item."Last Updated" := Today;
Item.Modify();
Counter += 1;
if Counter mod 100 = 0 then
Commit; // release locks every 100 records
until Item.Next() = 0;
Commit;
This small change has solved many performance issues for my customers.
2. Use surgical locking instead of LockTable()
Some developers still use LockTable() like it’s candy. Usually unnecessary.
Don’t do this:
Customer.LockTable();
Customer.FindSet();
Do this instead:
Customer.SetRange("No.", CustomerNo);
Customer.ReadIsolation := IsolationLevel::UpdLock;
Customer.FindFirst();
Much cleaner and less destructive for concurrency.
3. Never call HTTP inside a transaction
This one drives me crazy because I still see it in 2025. Always commit your data first, then make the external call. Otherwise one slow vendor API can freeze the entire system.
4. Watch out for number series bottlenecks
If you’re running high-volume document creation and the No. Series Line is a chokepoint, look at “Allow Gaps in Nos.” for non-regulated documents. It removes the single-file queue on number assignment. Don’t use it where regulation requires continuous numbering (Greek invoicing rules, for example, won’t tolerate gaps).
My Practical Rules After 15 Years on BC
Honestly the rules are pretty simple:
- Keep transactions short. Commit early, commit often.
- Lock only records you truly need.
- Never wait on external systems while holding locks.
- Commit strategically, not emotionally.
- Stop blaming SQL Server for bad AL design.
The new Database Locks page in v27 is excellent for diagnosis, but it won’t save badly designed customisations. The real solution is still in the quality of your AL code. Write clean code and you will rarely need to open that page at all.
If you are having blocking issues, the answer is almost never “buy more hardware.” It is usually one badly designed transaction holding too much for too long.

Director and Founder of GMSOFT, a Microsoft Dynamics partner serving the UK, Greece, and Italy. Microsoft Dynamics 365 Community Super User, Season 1 2026 — recognised for top-tier community contribution on Business Central manufacturing topics. Independent BC consultant with 15 years on Business Central and NAV (and 30 in ERP overall). Founder of two BC user groups: Business Central Greece on LinkedIn and Dynamics Business Central User Group Greece (Microsoft Community). Publisher of 3 apps on Microsoft AppSource (ABC Classification Manager, Vendor Dispute, BOM Architect) and open-source AL on GitHub (GmsoftLtd).
Discover more from Inside Business Central
Subscribe to get the latest posts sent to your email.
