← All articles

GTM Operations

The Account Owner and the Opportunity Owner Disagree on 2,000 Accounts

The scary headline was 2,087 broken accounts. The number that needed action was 9. Here is the classify-before-you-send build that gets you from one to the other.

· 13 min read

I ran one query and it came back with 2,087. Out of 3,045 accounts that had an open opportunity, 2,087 had an account owner who was not the opportunity owner. Two people, on paper, disagreeing about who owns the relationship. Presented raw, that number gets you a war room. Someone forwards it to the VP, the VP asks how ops let this happen, and now you are defending a crisis you manufactured by not finishing the analysis.

For years the reflex with a count like that was to send it. Run the mismatch query, watch four figures come back, and escalate before the number cools. That reflex is the whole problem. The finish is this: of those 2,087, exactly 1,983 were by-design renewals. The account belongs to the named account owner, and the renewal opportunity sits with a renewals rep or a CSM by policy. That is not a mismatch. That is the model working. Strip those out and you are left with 104. Read the 104, and about 9 were genuinely urgent, the kind where the wrong person is about to get paid on a deal they are not working, or a hot opportunity has no one driving it. Nine. The headline was 2,087. The work was 9.

That gap between the count and the work is not a rounding error. It is the entire job. Below is the same 2,087 dissolving down to the 9 that matter, one filter at a time. Watch the field collapse, then I will show you the build that produces every cut.

2,087
Raw mismatch count (the headline)
1,983
By-design renewals (the noise)
9
Genuinely urgent (the work)
Classify, do not count2,087 dissolves into the 9 that need action
2,087Raw mismatch count2,087 accounts where the account owner is not the opportunity owner. Send this and you start a war room.

That collapse is the argument. The many dots are the headline. The growing disc is the small, concentrated answer that was hiding inside it the whole time. Every step in the build below is one stage of that dissolve, and the framework near the bottom of this piece is the repeatable version of it: pull, define the by-design buckets, filter, hand-read the tail, then stand up a report so it never grows back into 2,000.

Why this is not a hygiene footnote

It is tempting to file owner mismatch under data cleanliness, next to missing phone numbers. It belongs in a different category entirely. Ownership decides two things that matter more than almost anything else in the CRM: who gets paid when the deal closes, and who is on the hook to follow up while it is open. Get it wrong and you either pay the wrong rep, which you find out about at commission true-up when it is a fight, or you have an opportunity that every rep assumes the other one is working, which is how deals go dark with a healthy-looking stage.

This is where the drift comes from in the first place. B2B contact and account data decays at roughly 30% a year (ZoomInfo), reps leave, territories move, and every one of those events reassigns an account without reassigning the open deals sitting on it. Gartner pegs the average cost of poor data quality at about $15M a year per organization. Ownership drift is a slice of that bill, and it accrues silently: nobody notices until a commission dispute or a dark deal forces the question.

So the mismatch matters. The 2,087 does not. The entire job is separating the by-design noise from the urgent few, because the count on its own tells leadership nothing except that ops should panic.

There is a real cost to reporting the raw number, and it is not only wasted meeting time. Experian found 55% of organizations say bad data undermines trust in their systems (Experian 2024 data quality research), and the fastest way to become part of that statistic is to escalate a 2,087 that turns out to be 9. The first time you do it, you spend credibility you do not get back cheaply. The next genuine four-figure problem you raise gets discounted, because the last one you raised evaporated under one filter. Ops earns the right to say “this is a real fire” by never crying fire over a number it had not finished reading.

The query, then the classification

Start with the raw pull. Any account with an open opportunity where the account’s OwnerId is not the opportunity’s OwnerId. In SOQL that is roughly:

SELECT Account.Name, Account.Owner.Name, Owner.Name,
       StageName, Type, RecordType.Name, Amount
FROM Opportunity
WHERE IsClosed = false
  AND Account.OwnerId != OwnerId
ORDER BY Amount DESC

That gives you the scary number. Now do the part that turns it into work, which is classification, not counting.

The by-design bucket is the biggest and you can define it precisely. Renewal-type opportunities where the opportunity owner is a renewals rep or CSM, that is policy, drop it. Opportunities inside a pooled or house book where account ownership is deliberately separate, policy, drop it. Anything where the mismatch follows a rule your team wrote on purpose is noise by definition, and you filter it with the opportunity Type, the owner’s role, and the record type.

Add the one filter that removes most of the pile:

SELECT Account.Name, Owner.Name, StageName, Amount
FROM Opportunity
WHERE IsClosed = false
  AND Account.OwnerId != OwnerId
  AND Type != 'Renewal'
  AND RecordType.Name != 'Renewal'
ORDER BY Amount DESC

In my pull, renewals alone were 1,983 of the 2,087. One filter took the problem from four figures to three. That single line is the second stage of the dissolve above: the field collapses from 2,087 dots to 104.

Here is where every one of those 2,087 rows went, so the cuts are named rather than asserted.

BucketCountFilter that isolates itAction
Renewal by policy1,983Type = 'Renewal' or renewal record typeDocument as expected, drop
Pooled / house book62Owner role in pooled bookNote, no action
Explained reassignment33Departed owner or pre-realignment create dateLog, batch-fix later
Genuinely urgent9Survives filters, high amount, no policy reasonFix by hand this week
Total2,087

What is left is the real bucket, and you read it by hand because it is small enough to. New-business opportunities where account and opp owner disagree with no policy reason. A rep who left, whose accounts got reassigned but whose open opportunities did not follow. A territory realignment that moved accounts and orphaned the deals on them. These are the ones where money and follow-up are genuinely at risk.

Each of those root causes leaves a fingerprint you can sort on, which is what makes the hand read fast rather than tedious. Departed-rep orphans cluster around users whose account is now inactive: sort the survivors by opportunity owner and the deactivated owners jump out as a block. Realignment orphans cluster in time, all created before a known territory change and never reassigned with the accounts, so a create-date sort surfaces them together. What is left after those two patterns is the genuinely ad-hoc handful, and by then you are reading a dozen rows, not a hundred. The filters do the volume work. Your judgment only has to touch the residue.

The amount column is the last cut

Not every one of the surviving mismatches deserves the same urgency, and this is the step that takes 104 down to 9. A $4K open opportunity with an ownership question is a note for the monthly report. A $400K open opportunity where nobody is sure who is working it is a same-week problem, because that is real forecast dollars sitting behind an ownership answer nobody has given. Sort the survivors by amount descending and the deals that can move the number float to the top.

Open amount bandNon-renewal survivorsTreatment
Over $250K4Same-week fix, forecast dollars at risk
$50K to $250K5This-month fix
Under $50K95Monthly report, batch-handle
Total1049 urgent, 95 routine

That is how 104 becomes 9: the 4 large deals plus the 5 mid deals are the ones where a wrong owner touches forecast or follow-up this quarter. The other 95 are real but not urgent, and they belong in a standing report, not an escalation. The amount column is the fastest tiebreak between “act now” and “track.”

The funnel from headline to work

Every scary CRM count funnels down the same way. The trick is doing the funnel before you send the number up, not after leadership has already reacted to the top of it.

Classify, do not count 2,087 headline down to 9 that need action this week
2,087 raw mismatches− renewals by policy (1,983)104 non-renewal− explained reassignments9 urgentthe only rows with money or follow-up at risk
Each cut is a filter you can name: opportunity Type, owner role, record type, then a hand read of the small tail. The headline is the mean of a bimodal pile.

Median and distribution beat the headline count

The instinct with a number like 2,087 is to report the number. The better move is to report the distribution, because the distribution is what tells the story honestly. Grouped by opportunity Type, my 2,087 was overwhelmingly renewals, and that single cut defused the whole thing. Grouped by amount, the urgent handful clustered where you would expect: a few large open deals with an ownership question, which is precisely where you want eyes.

The 2,087 grouped by opportunity type
The headline is the mean of a bimodal pile: mostly harmless renewals, a tiny tail of real risk. Reporting the pile as one number is as misleading as shipping a mean when you have two clusters.
View as table
ItemValue
Renewal (policy)1,983
Pooled / house book62
Explained reassign33
Urgent (action)9

The bimodal shape is the tell, and it shows up in almost every scary CRM count. You have a large, dense cluster of rows that look alarming but are working as designed, and a small, sparse tail of rows that are genuinely broken. A single count sits somewhere in the middle and describes neither cluster, exactly the way a mean describes neither peak of a two-humped distribution. Anyone who has been burned reporting a mean on bimodal data already knows the fix: show the shape. Show that 1,983 are by-design and 9 need action this week, and leadership stops reacting to the 2,087 and starts asking about the 9, which is the only conversation worth having.

Here’s how I’d build it: the scary-count triage

This is the pattern I run on any four-figure count before it leaves my hands. Five steps that turn a fire drill into a to-do list plus a standing report, and each step maps to one stage of the dissolve at the top: pull is the full field, filter is the collapse to 104, hand-read is the collapse to 9.

The scary-count triage
  1. 1

    1. Pull raw, but do not send it

    Run the mismatch query and get the count. Then close the tab. The raw 2,087 goes nowhere until it is classified. Sending it now is how you manufacture a crisis.

  2. 2

    2. Define the by-design buckets precisely

    Write down every rule that produces a mismatch on purpose: renewals owned by CSMs, pooled books, house accounts. Each becomes a filter on Type, owner role, or record type. This is the biggest bucket and it is noise.

  3. 3

    3. Filter the noise out

    Apply the by-design filters. In my pull one filter, Type is not Renewal, removed 1,983 of 2,087. What survives is small enough to read.

  4. 4

    4. Hand-read the tail and sort by amount

    Read the 104 survivors by row. Explained reassignments get noted and batched. Genuine risk, money or follow-up at stake, goes on the action list. Sort by amount so the 9 that move the forecast float to the top.

  5. 5

    5. Stand up a monthly report

    Turn the non-renewal set into a report someone owns, so next month surfaces 15 or 20 instead of accumulating into another 2,000-row fire drill. Document the 1,983 renewals as expected so the next person does not re-panic.

What I did with the 9

The 9 got fixed by hand, because 9 is a number you fix by hand. Reassign the opportunity to match the working rep, or reassign the account, depending on which one was wrong, and note why. The 104 non-renewal set became a monthly report someone owns, so the next batch surfaces at 15 or 20 instead of accumulating into another 2,000-row fire drill. The 1,983 renewals got documented as expected behavior so the next person who runs this query does not re-panic and re-escalate the same non-problem.

Report the count Report the classification
What leadership hears "2,087 accounts are broken" "1,983 by design, 9 need action"
The reaction War room, who let this happen Fix the 9, own the monthly report
Ops credibility Manufactured a crisis Turned a count into a to-do list
Next quarter Someone re-runs it and re-panics Documented, surfaces at 15 not 2,000
Same query, same 2,087 rows. One triggers a war room, one produces nine fixes and a standing report.

That is the pattern for any scary count in the CRM. Run the query, then refuse to report it until you have classified it. The headline number is almost never the work. The work is the small, ugly tail you only find by filtering out everything that was supposed to look that way, the 9 dots left standing after the other 2,078 dissolve. For the field-level version of this same discipline, see the required-fields tax. And because ownership drift is mostly a reassignment problem, the standing fix lives in how you move territories without orphaning the deals on them: see territory without mutiny.

salesforce account-ownership

Keep reading

One email. Every week.

One email a week: an operating problem I solved or botched, with the model, the numbers, and what I would change. No roundups, no theory, unsubscribe whenever it stops being useful.

The newsletter opens soon.

Connect a provider in src/config.ts