The hosts took the lead a minute before the break when Niclas Eliasson’s cross from the left was met with a firm downward header from Kasey Palmer but Boro equalised after 64 minutes, Taylor Moore diverting Paddy McNair’s low cross into his own net.
Woodgate’s men added another four minutes later through Britt Assombalonga’s assured left-footed finish but City hit back nine minutes from time when substitute Callum O’Dowda crossed for the unmarked Tommy Rowe to net with a stooping header.
Woodgate said: “I thought we were the better side and deserved to win. It was a top-class performance and our best of the season so far.
“I haven’t a bad word to say about any of my players. Bristol looked to counter-attack us and did so effectively in the first half, but we tweaked a couple of things at half-time and I thought the lads were outstanding in terms of effort. Of course, I’m unhappy with conceding from two headers. Defenders seem to want to mark areas rather than opponents these days and space never scored a goal.
“There were some tremendous performances. Britt Assombalonga’s missus gave birth on Thursday and I wish she would do so every week because he was immense.
“Dael Fry gave a real captain’s display. He is the sort of guy I want as a leader.”
Bristol City: Bentley, Hunt (Pereira 67), Moore, Baker, Rowe, Eliasson, Brownhill, Massengo (Semenyo 74), Palmer (O’Dowda 66), Weimann, Afobe. Unused substitutes: Diedhiou, Szmodics, Williams, Maenpaa.
Middlesbrough: Randolph, Dijksteel, Fry, Shotton, Bola, McNair, Clayton, Wing, Johnson (Saville 82), Assombalonga, Fletcher (Gestede 90). Unused substitutes: Tavernier, Browne, Malley, Walker, Pears.
Referee: L Mason (Lancashire).