Pakistan, trailing 1-0 in the three-match series, took advantage of the surprise decision by Mahela Jayawardene, the Sri Lanka captain, to field first on a good batting track at the Sinhalese Sports Club.
Hafeez led the Pakistani charge with his fifth Test century - and the first after 10 innings - as the tourists moved to a commanding 334 for one by stumps on the opening day.
The Pakistan vice-captain has put on 256 for the unbroken second wicket with Azhar Ali (92 not out) after sharing an opening stand of 78 with Taufeeq Umar (65).
It was the first time since making 379 for four against India in Faisalabad in 2006 that Pakistan scored over 300 runs on the first day of a Test match.
Hafeez's ton helped overcome the sting of losing the first Test by 209 runs in Galle, where he led Pakistan in the absence of the banned Misbah-ul-Haq.
The all-rounder had been under pressure to retain his place in the Test side after a barren run since making his previous best of 143 against Bangladesh in Chittagong last year.
Hafeez smashed 18 boundaries and a six off Suraj Randiv that sailed over the midwicket fence.
"Finally, I did something good for my team," Hafeez said. "I have been working hard at the nets. It was tough not to be scoring because the top order has to perform in these conditions.
"I was under pressure, but Taufeeq lifted some of it by his superb batting and then Azhar came and gave me solid support. I just needed some luck and it all came good today."
Azhar was content to play second fiddle at the other end, scoring just six fours, as the second-wicket pair laid the foundation for a big first-innings total. Azhar will resume today needing just eight runs to complete his third Test century.
Graham Ford, Sri Lanka's South African coach, conceded the decision to field first backfired, but insisted a lot of thought had gone into taking that call.
"Clearly, we got that wrong, but no one thought the pitch will play so well in the first hour," Ford said. "If we had got some early wickets, we would have put Pakistan under pressure.
"The decision to field was not taken lightly. There was a lot of discussion and debate and we all felt it was worth having a crack at the ball. But it did not work out the way we wanted.
"We must give credit to the Pakistan batsmen for playing so well. We now have a lot of work to do."
Hafeez earned a break just before tea when he was caught down the leg-side by the wicketkeeper Prasanna Jayawardene, but television replays confirmed Angelo Mathews had sent down a no-ball.
When Hafeez was on 171, the umpire Simon Taufel turned down Rangana Herath's confident appeal for a catch at the wicket even as TV replays indicated the ball may have gone off the bat.
Follow us @SprtNationalUAE