This is Follow the Money, our weekly series that unpacks the earnings, business, and scaling strategies of African fintechs, financial institutions, companies, and governments. A new edition drops every Monday.
For a small business in Nigeria, securing a bank loan has long felt like trying to step through a moving doorway.
Commercial banks mobilise deposits, and the Central Bank of Nigeria (CBN) urges them to extend credit, yet formal lending to small businesses remains low.
According to World Bank data, micro, small, and medium-sized enterprises (MSMEs) form the backbone of the economy, accounting for the vast majority of businesses, nearly half of national GDP, and most employment. Yet fewer than one in 20 MSMEs can access formal bank credit due to entrenched structural barriers.
The credit that is available is predominantly short-term and expensive, while prohibitive collateral requirements disqualify otherwise viable enterprises.
For commercial banks, credit extension is a risk-return decision. While a bank earns interest on disbursed capital, the lending rates it charges are governed by several variables—chief among them the CBN’s Monetary Policy Rate (MPR), which sets the baseline cost of capital across the economy.
When the CBN raises the MPR, commercial banks adjust their prime lending rates upward, making credit more costly. Conversely, rate cuts are intended to lower borrowing costs and stimulate economic activity.
The apex bank adjusts benchmark rates primarily to regulate inflation and systemic liquidity. When price pressures surge, the CBN tightens monetary policy through rate hikes; when inflation moderates, it eases policy to encourage growth.
This macroeconomic lever directly affects small businesses. Elevated rates raise the cost of capital and deter expansion, whereas rate cuts are theoretically designed to democratise access to credit.
On Tuesday, the CBN delivered its biggest single interest-rate cut on record, slashing the benchmark MPR by 3.5 percentage points to 23%.
However, historical data call into question whether benchmark rate cuts actually translate into increased bank lending for small businesses.
TechCabal analysed a decade of CBN data to examine how lending to small businesses responded as the benchmark interest rate changed.
What happens when the CBN changes its rate?
A rate cut can lower the cost of money. But getting that cheaper money into an SME’s hands depends on what happens between the CBN and the borrower.
20.0%
Cut
23.0%
Current
27.0%
Hike
CBN
BANK
LOAN
SME
Same MPR. Different borrower.
Tap a factor to see how it shifts the credit decision
Collateral
Cash flow
History
Lower uncertainty
More info available
Higher uncertainty
Less info available
So, does a lower MPR mean more SME lending?
Not necessarily.
That’s what TechCabal’s 10-year look at CBN data tests next.
A decade of MPR movements and SME credit allocation
Between 2015 and 2025, commercial bank lending to SMEs expanded 1,270.19%, reaching ₦177.44 billion ($133.46 million). Despite this expansion, SME loans as a proportion of total commercial bank credit remained marginal, rising only slightly from 0.10% in 2015 to 0.38% in 2025. The total bank volume allocated to SMEs pales in comparison to the ₦47.09 trillion ($35.42 billion) extended to the broader private sector in 2025, where commercial credit remained concentrated in oil and gas, financial services, and general commerce.
Over the decade, the CBN monetary policy stance underwent distinct operational shifts. Initial years of monetary easing were followed by pandemic-era interventions in 2020, during which the central bank slashed rates and rolled out targeted liquidity facilities. Then inflation changed the equation. As prices accelerated, the CBN began aggressively tightening monetary policy, pushing the MPR to 27.50% in 2024.
On the surface, this should have made borrowing more expensive and potentially reduced demand for loans. But the decade-long data tells a more nuanced story.
In 2015, when the MPR was 11%, banks’ loans to SMEs stood at ₦12.95 billion ($9.74 million). When the MPR rose to 14% in 2016, SME lending fell to ₦10.75 billion ($8.09 million) and remained there in 2017.
When rates moved, SME lending didn’t always follow.
Explore 10 years of CBN data to see how the Monetary Policy Rate moved against commercial-bank lending to small businesses.
Actual values
2015 Baseline
2015
2018
2021
2025
2015
2025
The baseline year. MPR stood at 11.0%, and commercial-bank SME lending was ₦12.95 billion.
2018
The first divergence
2020
The pandemic shock
2023
The contradiction
The numbers show that the MPR and SME lending moved together in some periods and in opposite directions in others.
This suggests that MPR alone does not explain how much Nigerian banks lend to small businesses. Banks make lending decisions based on more than the CBN’s benchmark rate. They consider the cost of deposits, inflation, credit risk, collateral, liquidity, regulatory requirements, and the likelihood that a borrower will repay.
They also favour more predictable businesses. Many small businesses have weak financial records, compared to those in the private sector.
Loans to the private sector only fell in 2018, before falling again in 2025. Unlike for small businesses, the MPR did not deter banks from lending to the private sector.
The 1% Reality: SME Loans vs. Total Private-Sector Credit
The money in Nigeria’s banking system has grown dramatically, but SME lending remains a microscopic slice. Scrub across the chart to see the relationship between total private-sector credit and SME loans.
Relative Growth
Zoom into SME
Compare Years
`;
});
group.innerHTML = `
`;
bindInteraction();
render();
}
function calculateY(val, isTot) {
let max;
if (state.mode === ‘actual’) {
max = state.zoomSME ? (maxActSme * 1.15) : (maxActTot * 1.1);
} else {
max = maxRel * 1.1;
}
const normalized = (val / max);
return BASE_Y – (normalized * (BASE_Y – TOP_Y));
}
function getVal(i, isTot) {
if (state.mode === ‘actual’) return isTot ? tcData[i].tot : tcData[i].sme;
return isTot ? relData[i].tot : relData[i].sme;
}
function render() {
let dTot = “”, dSme = “”, aTot = “”, aSme = “”;
const step = (C_W – (PAD_X * 2)) / (tcData.length – 1);
tcData.forEach((d, i) => {
const x = PAD_X + (i * step);
const yTot = calculateY(getVal(i, true), true);
const ySme = calculateY(getVal(i, false), false);
const cmd = i === 0 ? “M” : “L”;
dTot += `${cmd} ${x} ${yTot} `;
dSme += `${cmd} ${x} ${ySme} `;
if (i === 0) {
aTot += `M ${x} ${BASE_Y} L ${x} ${yTot} `;
aSme += `M ${x} ${BASE_Y} L ${x} ${ySme} `;
} else {
aTot += `L ${x} ${yTot} `;
aSme += `L ${x} ${ySme} `;
}
if (i === tcData.length – 1) {
aTot += `L ${x} ${BASE_Y} Z`;
aSme += `L ${x} ${BASE_Y} Z`;
}
});
document.getElementById(‘tc-path-tot’).setAttribute(‘d’, dTot);
document.getElementById(‘tc-area-tot’).setAttribute(‘d’, aTot);
document.getElementById(‘tc-path-sme’).setAttribute(‘d’, dSme);
document.getElementById(‘tc-area-sme’).setAttribute(‘d’, aSme);
const ghost = document.getElementById(‘tc-path-ghost’);
if (state.mode === ‘actual’ && state.zoomSME) {
let dGhost = “”;
tcData.forEach((d, i) => {
const x = PAD_X + (i * step);
const normalized = (d.tot / (maxActTot * 1.1));
const yG = BASE_Y – (normalized * (BASE_Y – TOP_Y));
dGhost += `${i === 0 ? “M” : “L”} ${x} ${yG} `;
});
ghost.setAttribute(‘d’, dGhost);
ghost.style.opacity = ‘1’;
} else {
ghost.style.opacity = ‘0’;
}
const yLbl = document.getElementById(‘tc-y-axis-label’);
if (state.mode === ‘actual’) yLbl.textContent = state.zoomSME ? ‘Amount in ₦ Billions (Zoomed)’ : ‘Amount in ₦ Billions’;
else yLbl.textContent = ‘Indexed Growth (2015 = 100)’;
updateHUD();
updateEditorial();
}
function updateHUD() {
const d1 = tcData[state.yr1Index];
const step = (C_W – (PAD_X * 2)) / (tcData.length – 1);
// 1. Move Primary Marker on Chart
const pctX1 = (PAD_X + (state.yr1Index * step)) / C_W * 100;
document.getElementById(‘tc-marker-primary’).style.transform = `translateX(${pctX1}%)`;
document.getElementById(‘tc-marker-primary’).style.opacity = ‘1’;
const pctYTot1 = (calculateY(getVal(state.yr1Index, true), true) / C_H) * 100;
const pctYSme1 = (calculateY(getVal(state.yr1Index, false), false) / C_H) * 100;
document.getElementById(‘tc-pt-tot-1’).style.top = `${Math.max(pctYTot1, -5)}%`;
document.getElementById(‘tc-pt-sme-1’).style.top = `${pctYSme1}%`;
// 2. Update Primary HUD Text
document.getElementById(‘tc-hud-year-1’).textContent = d1.year;
document.getElementById(‘tc-hud-tot-1’).textContent = state.mode === ‘actual’ ? `₦${(d1.tot/1000).toFixed(2)}T` : `${getVal(state.yr1Index, true).toFixed(0)} (Idx)`;
document.getElementById(‘tc-hud-sme-1’).textContent = state.mode === ‘actual’ ? `₦${d1.sme.toFixed(2)}B` : `${getVal(state.yr1Index, false).toFixed(0)} (Idx)`;
document.getElementById(‘tc-hud-share-1’).textContent = `${d1.share.toFixed(2)}%`;
const hudContainer = document.getElementById(‘tc-hud-scoreboard’);
// 3. Handle Compare Mode
const compSection = document.getElementById(‘tc-hud-compare-section’);
const marker2 = document.getElementById(‘tc-marker-secondary’);
if (state.compare) {
const d2 = tcData[state.yr2Index];
compSection.style.display = ‘block’;
marker2.style.display = ‘block’;
// Move Secondary Marker
const pctX2 = (PAD_X + (state.yr2Index * step)) / C_W * 100;
marker2.style.transform = `translateX(${pctX2}%)`;
marker2.style.opacity = ‘1’;
const pctYTot2 = (calculateY(getVal(state.yr2Index, true), true) / C_H) * 100;
const pctYSme2 = (calculateY(getVal(state.yr2Index, false), false) / C_H) * 100;
document.getElementById(‘tc-pt-tot-2’).style.top = `${Math.max(pctYTot2, -5)}%`;
document.getElementById(‘tc-pt-sme-2’).style.top = `${pctYSme2}%`;
// Update Secondary HUD Text
document.getElementById(‘tc-hud-year-2’).textContent = d2.year;
document.getElementById(‘tc-hud-tot-2’).textContent = state.mode === ‘actual’ ? `₦${(d2.tot/1000).toFixed(2)}T` : `${getVal(state.yr2Index, true).toFixed(0)} (Idx)`;
document.getElementById(‘tc-hud-sme-2’).textContent = state.mode === ‘actual’ ? `₦${d2.sme.toFixed(2)}B` : `${getVal(state.yr2Index, false).toFixed(0)} (Idx)`;
document.getElementById(‘tc-hud-share-2’).textContent = `${d2.share.toFixed(2)}%`;
hudContainer.style.borderTopColor = ‘#8B949E’;
document.getElementById(‘tc-hud-label-1’).textContent = ‘Primary Selection’;
} else {
compSection.style.display = ‘none’;
marker2.style.display = ‘none’;
hudContainer.style.borderTopColor = ‘#24292F’;
document.getElementById(‘tc-hud-label-1’).textContent = ‘Selected Year’;
}
}
function updateEditorial() {
const bar = document.getElementById(‘tc-editorial-bar’);
const text = document.getElementById(‘tc-editorial-text’);
const d1 = tcData[state.yr1Index];
if (state.compare) {
text.innerHTML = `Comparing ${tcData[state.yr2Index].year} and ${d1.year}. View the summary box below for absolute changes.`;
bar.style.borderLeftColor = ‘#8B949E’;
return;
}
if (state.mode === ‘relative’) {
text.innerHTML = `From a 2015 baseline, SME lending grew nominally by ${getVal(state.yr1Index, false).toFixed(0)}x by ${d1.year}, but total credit also expanded massively, masking the gains.`;
bar.style.borderLeftColor = ‘#24292F’;
return;
}
if (state.zoomSME && d1.year !== 2023) {
text.innerHTML = `Zooming in makes the SME trajectory visible, but look at the dotted ghost line: total credit has shot completely off the top of the chart.`;
bar.style.borderLeftColor = ‘#EA2D2E’;
return;
}
if (d1.year === 2023) {
text.innerHTML = `2023 recorded the highest SME share in this series: 1.18%. Even at its absolute peak, nearly 99% of private-sector credit went elsewhere.`;
bar.style.borderLeftColor = ‘#FFC52F’;
} else if (d1.year === 2024 || d1.year === 2025) {
text.innerHTML = `By ${d1.year}, the SME share fell to ${d1.share.toFixed(2)}%. The gap between total credit and SME support widened significantly after the 2023 peak.`;
bar.style.borderLeftColor = ‘#EA2D2E’;
} else {
text.innerHTML = `In ${d1.year}, SME loans constituted just ${d1.share.toFixed(2)}% of total credit. A visual rounding error in the macro economy.`;
bar.style.borderLeftColor = ‘#24292F’;
}
}
function updateCompareSummary() {
const box = document.getElementById(‘tc-compare-summary’);
const txt = document.getElementById(‘tc-compare-text’);
if (!state.compare) {
box.style.display = ‘none’;
return;
}
const d1 = tcData[Math.min(state.yr1Index, state.yr2Index)];
const d2 = tcData[Math.max(state.yr1Index, state.yr2Index)];
box.style.display = ‘block’;
const totGrow = (((d2.tot – d1.tot) / d1.tot) * 100).toFixed(1);
const smeGrow = (((d2.sme – d1.sme) / d1.sme) * 100).toFixed(1);
const shareDiff = (d2.share – d1.share).toFixed(3);
const dir = shareDiff >= 0 ? ‘grew’ : ‘fell’;
txt.innerHTML = `Between ${d1.year} and ${d2.year}, total private-sector credit grew by ${totGrow}%.
Nominal SME lending grew by ${smeGrow}%.
As a result, the SME share of the total credit pool ${dir} by ${Math.abs(shareDiff)} percentage points (from ${d1.share.toFixed(2)}% to ${d2.share.toFixed(2)}%).`;
}
function bindInteraction() {
const layer = document.getElementById(‘tc-interaction-layer’);
function getIndex(clientX, rect) {
const xPos = clientX – rect.left;
const pct = xPos / rect.width;
let idx = Math.round(pct * (tcData.length – 1));
return Math.max(0, Math.min(idx, tcData.length – 1));
}
function handleMove(e) {
e.preventDefault();
const rect = layer.getBoundingClientRect();
let clientX = e.clientX;
if (e.touches && e.touches.length > 0) clientX = e.touches[0].clientX;
const idx = getIndex(clientX, rect);
if (state.yr1Index !== idx) {
state.yr1Index = idx;
render();
}
}
layer.addEventListener(‘mousemove’, handleMove);
layer.addEventListener(‘touchmove’, handleMove, {passive: false});
layer.addEventListener(‘click’, (e) => {
if (!state.compare) return;
const rect = layer.getBoundingClientRect();
const idx = getIndex(e.clientX, rect);
state.yr2Index = idx;
render();
});
// Handle resize to update X-Axis format
window.addEventListener(‘resize’, () => {
const group = document.getElementById(‘tc-html-x-axis’);
const isMobile = window.innerWidth < 500;
Array.from(group.children[0].children).forEach((child, i) => {
child.textContent = isMobile ? `’${String(tcData[i].year).slice(2)}` : tcData[i].year;
});
});
}
window.tcSetMode = function(mode) {
state.mode = mode;
document.getElementById(‘tc-btn-actual’).classList.toggle(‘tc-active-scale’, mode === ‘actual’);
document.getElementById(‘tc-btn-relative’).classList.toggle(‘tc-active-scale’, mode === ‘relative’);
const zoomToggle = document.getElementById(‘tc-zoom-toggle’);
if (mode === ‘relative’) {
zoomToggle.disabled = true;
zoomToggle.checked = false;
state.zoomSME = false;
zoomToggle.parentElement.style.opacity = ‘0.5’;
} else {
zoomToggle.disabled = false;
zoomToggle.parentElement.style.opacity = ‘1’;
}
render();
};
window.tcToggleZoom = function(isChecked) {
state.zoomSME = isChecked;
if (state.mode === ‘actual’) render();
};
window.tcToggleCompare = function(isChecked) {
state.compare = isChecked;
if (isChecked && state.yr1Index === state.yr2Index) {
state.yr2Index = 0;
}
render();
updateCompareSummary();
};
if (document.readyState === ‘loading’) {
document.addEventListener(‘DOMContentLoaded’, initChart);
} else {
initChart();
}
})();
