How to Fix MetaMask Pending Transactions
In this tutorial, you'll learn about How to Fix MetaMask Pending Transactions. We cover key concepts, practical examples, and best practices.
The Problem
Your MetaMask transaction is stuck in "Pending" status for hours. The Activity tab shows a spinning icon, and subsequent transactions also hang because they use the same nonce. The transaction cannot be cancelled or sped up properly.
Quick Fix
Fix 1: Speed Up the Transaction
WRONG — clicking "Speed Up" without raising gas enough:
# (MetaMask suggests a small gas increase, but if the network is congested,
# even the increased gas may not be enough)
RIGHT — manually set a high gas price when speeding up:
# 1. In MetaMask, click on the pending transaction
# 2. Click "Speed Up"
# 3. Click "Edit" next to gas price
# 4. Set gas price to at least 2x the current base fee + priority fee
# 5. Confirm
Fix 2: Cancel the Transaction
# 1. In MetaMask, click the pending transaction
# 2. Click "Cancel"
# 3. Confirm the cancellation
# (this sends a 0 ETH transaction with the same nonce and higher gas)
If MetaMask's cancel does not work, do it manually:
// Using ethers.js:
const tx = {
to: "0x0000000000000000000000000000000000000000",
value: 0,
nonce: stuckNonce, // same nonce as the stuck transaction
gasLimit: 21000,
maxPriorityFeePerGas: ethers.parseUnits("50", "gwei"),
maxFeePerGas: ethers.parseUnits("100", "gwei"),
};
const replacementTx = await signer.sendTransaction(tx);
await replacementTx.wait();
// (this replaces the stuck transaction)
Fix 3: Clear Pending Transactions in MetaMask
If the transaction is stuck client-side:
# MetaMask Settings → Advanced → Clear activity tab data
# This clears the local transaction history (does not affect the blockchain)
# The transaction may still be pending on-chain
Fix 4: Use the Nonce Directly
// Get the current nonce from an external block explorer:
// etherscan.io/address/YOUR_ADDRESS → check "Nonce" tab
// In ethers.js, manually set the nonce:
const currentNonce = await provider.getTransactionCount(signer.address);
const tx = await signer.sendTransaction({
to: "0x...",
value: ethers.parseEther("0.1"),
nonce: currentNonce, // use the latest nonce
gasLimit: 21000,
});
Fix 5: Transaction Replacement Underpriced
// Error: "replacement transaction underpriced"
// (the gas price on the replacement is not high enough)
Reference: the replacement must pay at least 10% more gas than the stuck transaction.
const stuckTx = await provider.getTransaction(stuckTxHash);
const minGasPrice = stuckTx.gasPrice * 110n / 100n; // 10% more
const replacement = await signer.sendTransaction({
to: "0x0000000000000000000000000000000000000000",
value: 0,
nonce: stuckTx.nonce,
gasPrice: minGasPrice,
gasLimit: 21000,
});
Fix 6: Nonce Pool Too Low (Out of Order)
// Transaction with nonce 5 is stuck → nonce 6 and 7 also cannot proceed
// (Ethereum processes transactions in nonce order)
Fix all pending nonces by replacing each stuck one.
// Cancel all transactions from nonce startNonce to currentNonce:
for (let nonce = startNonce; nonce < currentNonce; nonce++) {
const pendingTx = await provider.getTransaction(signer.address, nonce);
if (pendingTx && pendingTx.blockNumber === null) {
// Send a 0 ETH replacement with higher gas
await signer.sendTransaction({
to: "0x0000000000000000000000000000000000000000",
value: 0,
nonce: nonce,
gasPrice: pendingTx.gasPrice * 120n / 100n,
gasLimit: 21000,
});
}
}
Use DodaTech's Transaction Monitor to track pending transactions, receive alerts when gas is too low, and automatically replace stuck transactions.
Prevention
- Set realistic gas prices using
eth_feeHistoryor gas oracles. - Do not send multiple transactions from the same account simultaneously.
- Always check the current base fee before sending.
- Use
maxPriorityFeePerGasandmaxFeePerGas(EIP-1559) instead ofgasPrice. - Keep a small ETH buffer for replacing stuck transactions.
Common Mistakes with pending tx
- Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable
- Using
headandtailinstead of pattern matching, causing runtime errors on empty lists - Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
These mistakes appear frequently in real-world METAMASK code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro