Russell called a switch onto a one-stop strategy, an inspired decision as he beat Hamilton by just half a second.
A charging last stint from Piastri left him agonisingly short of a second win, taking the chequered flag within a second of Hamilton as the top three were split by just 1.1s after 44 laps.
Max Verstappen recovered to fifth while a first corner mistake proved costly for Lando Norris who could do no better than sixth.
Sergio Perez meanwhile slipped from the front row to eighth in a poor performance from the Mexican, while Daniel Ricciardo narrowly missed out on the points in 11th.
At the race start, Charles Leclerc jumped well to hold the lead, Hamilton drawing alongside Perez into La Source.
On exit, Norris ran wide, dropping a wheel into the gravel as he fell behind Carlos Sainz into seventh.
Leclerc held the lead at Turn 1 as Perez attacked Hamilton while Piastri went wheel to wheel with Russell at Les Combes.
The Mercedes driver ran through the run-off, rejoining behind the McLaren in what was a frantic opening to the race.
At the end of the opening lap, Leclerc headed Hamilton from Perez, Piastri, Russell, Sainz, Norris, Fernando Alonso, and Verstappen in ninth – a two place gain from his grid spot.
Norris put a move on Sainz at Les Combes on Lap 2 but couldn’t pull up the McLaren as fell back behind the Ferrari.
That allowed Verstappen to latch on to his rear wing by the end of the lap, the Red Bull Racing driver having found a way by Alonso.
On Lap 3, Leclerc lost the lead as Hamilton used DRS to cruise by on the Kemmel Straight.
Soon after, Zhou Guanyu’s race was dealt a blow as he rolled through the middle sector, reporting a loss of power in the Sauber.
He was able to get the car going once more but lost two-thirds of a lap in the process, though it was a stay of execution as he ultimately retired two laps later.
Out front, the leading eight cars ran in a DRS train, though Hamilton just clear enough to remain out of danger from Leclerc in second.
Perez dropped out of range of Leclerc on Lap 5, allowing Piastri an opportunity to attack into Les Combes.
Showing the nose, the Australian was unable to make the move stick as the Red Bull Racing driver began to lose contact with the two ahead.
Nico Hulkenberg pitted on Lap 7 to trigger the opening round of stops, Ricciardo following him into the lane a lap later.
The Australian was the only driver to have started on the soft compound tyre, the bulk having opted for the mediums.
Verstappen pulled the trigger at the end of Lap 11, Red Bull Racing looking to undercut the train ahead as he swapped from medium tyres to hards.
Russell had also stopped, taking on hard tyres and feeding out in the wheel tracks of Yuki Tsunoda.
He quickly cleared the RB driver, though Verstappen found it more difficult as the race leaders pitted to cover off the threat he and Russell posed.
Piastri lost ground in the cycle, though was able to immediately attack Russell to claim ninth on Lap 12 at Les Combes.
Ahead of him, Perez was stuck behind Lance Stroll’s Aston Martin, affording Piastri an opportunity to attack the Red Bull Racing driver.
Leclerc remained out, Ferrari pitting him at the end of Lap 12 to leave Sainz (on the hard tyres) in the race lead.
The Monegasque rejoined behind Hamilton, just clear of the Perez/Piastri battle. That was resolved in favour of the Australian on Lap 13.
Losing more than a second a lap over those who’d stopped, Norris finally pitted at the end of Lap 15.
That left Sainz as the last driver to stop, leading from Hamilton, Leclerc, Piastri, Perez, Russell, Verstappen, and Norris.
In the pack, Ricciardo had climbed into the top 10 and found himself stuck behind Alex Albon’s Williams.
After 20 laps, Sainz finally pitted, taking on a set of medium tyres to feed out into a lonely eighth place.
Up the road, Perez lost out to Russell as the Mercedes driver used DRS to cruise by on the Kemmel Straight on Lap 21.
The Mexican quickly slipped back from the Mercedes, Verstappen stuck behind him and losing time in the process.
Red Bull boxed Perez at the end of the lap to swap onto the hard tyres to feed out in front of Albon in eighth.
At the halfway point, Hamilton headed Leclerc by almost two seconds, with Piastri 2.5s back in third.
Then came Russell, four seconds back, followed by Verstappen, Norris, Sainz, and Perez.
Ricciardo had stopped a second time, dropping to 17th in a move designed to undercut Albon in their battle for ninth.
Leclerc took service for a second time on Lap 25, a comparatively sluggish 3.4s stationary time.
Mercedes responded by pitting Hamilton from the lead on the next lap, his stop a second faster to maintain his advantage over the Ferrari driver.
That left Piastri out front but yet to serve his second stop, the McLaren driver promptly setting the fastest lap of the race as he extended his middle stint.
Verstappen was in the lane for a second time at the end of Lap 28, rejoining seventh, just under two seconds behind team-mate Perez.
Norris was in next time around, the Brit out behind the two Red Bulls.
McLaren hauled Piastri in from the lead at the end of Lap 30, though he slid long in his pit box for a stationary time of 4.4s.
Crucially, he remained ahead of Perez as he fed out in fourth, around 14s back from Russell in the race lead.
Hamilton was second, seven seconds back, with Leclerc third at 2.4s back.
Russell had swapped to a one-stop strategy, a gamble made with a view to stealing a podium position.
He was losing time to team-mate Hamilton by around seven-tenths a lap, with Leclerc slipping back from the second Mercedes and into the clutches of Piastri similarly quickly.
On Lap 35, Piastri used DRS to attack the Ferrari into Les Combes, but was held wide as Leclerc maintained the racing line to retain the position.
A lap later, he went the long way around to steal the place – an important move in the context of the fight for the race lead.
Even with the scrap with Leclerc, the McLaren driver had only lost two-tenths on Hamilton ahead, with a 5.5s gap to bridge and eight laps in which to do it.
Russell was a further 2.8s up the road, but running almost a second slower than his Mercedes team-mate.
On 39, Perez fell to eighth as Sainz moved by on the Kemmel Straight in what was an underwhelming performance given he’d started on the front row.
With five laps remaining, Russell held just over a second advantage to Hamilton, with Piastri 4.9s back from the Mercedes, and closing at six-tenths a lap.
The instruction from the Mercedes pit wall was that its drivers were free to race, the pair appearing to have the chasing McLaren covered as the laps ticked down.
Behind them, Leclerc was under pressure to hold fourth, with Verstappen in his slipstream and Norris also in tow.
With three laps to go, Hamilton was easily within DRS range of Russell while Piastri was only three seconds back.
The seven-time champ was too far back to make a move into Les Combes, remaining in his team-mate’s wheel tracks as the McLaren moved to within two seconds of Hamilton at the end of the lap.
Piastri was nine tenths faster than either Mercedes, Hamilton making a mistake into La Source that left him stuck behind Russell, too far back to attack into Les Combes.
As the final lap began, there was little between the top three; Russell six-tenths ahead of Hamilton, with Piastri just 0.053s outside of DRS range of Hamilton as they flashed across the line.
A lock-up from Hamilton into La Source cost him valuable metres to the back of Russell, though Piastri was just too far back to make any impact.
It allowed Russell to hang on, Hamilton five-tenths shy of his team-mate with Piastri third in a nail-biting finish.
Leclerc held on to fourth from Verstappen and Norris, with Sainz seventh and Perez a disappointing eighth.
Alonso finished ninth while a fresh-booted Esteban Ocon stole the last point from Ricciardo in the final laps.